From 99a282f6319d0c7642f589163b955a636610719a Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Sat, 6 Nov 2021 16:05:33 -0500 Subject: Move and organize tests into subfolders --- tests/servers/test_physics_2d.cpp | 398 +++++++++++++++++++++++++++++++++++ tests/servers/test_physics_2d.h | 41 ++++ tests/servers/test_physics_3d.cpp | 410 +++++++++++++++++++++++++++++++++++++ tests/servers/test_physics_3d.h | 41 ++++ tests/servers/test_render.cpp | 232 +++++++++++++++++++++ tests/servers/test_render.h | 41 ++++ tests/servers/test_shader_lang.cpp | 360 ++++++++++++++++++++++++++++++++ tests/servers/test_shader_lang.h | 41 ++++ tests/servers/test_text_server.h | 296 ++++++++++++++++++++++++++ 9 files changed, 1860 insertions(+) create mode 100644 tests/servers/test_physics_2d.cpp create mode 100644 tests/servers/test_physics_2d.h create mode 100644 tests/servers/test_physics_3d.cpp create mode 100644 tests/servers/test_physics_3d.h create mode 100644 tests/servers/test_render.cpp create mode 100644 tests/servers/test_render.h create mode 100644 tests/servers/test_shader_lang.cpp create mode 100644 tests/servers/test_shader_lang.h create mode 100644 tests/servers/test_text_server.h (limited to 'tests/servers') diff --git a/tests/servers/test_physics_2d.cpp b/tests/servers/test_physics_2d.cpp new file mode 100644 index 0000000000..b6360cde8a --- /dev/null +++ b/tests/servers/test_physics_2d.cpp @@ -0,0 +1,398 @@ +/*************************************************************************/ +/* test_physics_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "test_physics_2d.h" + +#include "core/os/main_loop.h" +#include "servers/physics_server_2d.h" +#include "servers/rendering_server.h" + +static const unsigned char convex_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0xaa, 0x69, 0x71, 0xde, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf9, 0x43, 0xbb, 0x7f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xdb, 0x6, 0xa, 0x3, 0x13, 0x31, 0x66, 0xa7, 0xac, 0x79, 0x0, 0x0, 0x4, 0xef, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0x9b, 0xdd, 0x4e, 0x2a, 0x57, 0x14, 0xc7, 0xf7, 0x1e, 0xc0, 0x19, 0x38, 0x32, 0x80, 0xa, 0x6a, 0xda, 0x18, 0xa3, 0xc6, 0x47, 0x50, 0x7b, 0xa1, 0xd9, 0x36, 0x27, 0x7e, 0x44, 0xed, 0x45, 0x4d, 0x93, 0x3e, 0x40, 0x1f, 0x64, 0x90, 0xf4, 0x1, 0xbc, 0xf0, 0xc2, 0x9c, 0x57, 0x30, 0x4d, 0xbc, 0xa8, 0x6d, 0xc, 0x69, 0x26, 0xb5, 0x68, 0x8b, 0x35, 0x7e, 0x20, 0xb4, 0xf5, 0x14, 0xbf, 0x51, 0x3c, 0x52, 0xe, 0xc, 0xe, 0xc8, 0xf0, 0xb1, 0x7a, 0x51, 0x3d, 0xb1, 0x9e, 0x19, 0x1c, 0x54, 0x70, 0x1c, 0xdc, 0x9, 0x17, 0x64, 0x8, 0xc9, 0xff, 0xb7, 0xd6, 0x7f, 0xcd, 0x3f, 0x2b, 0xd9, 0x8, 0xbd, 0x9c, 0xda, 0x3e, 0xf8, 0x31, 0xff, 0xc, 0x0, 0x8, 0x42, 0x88, 0x9c, 0x9f, 0x9f, 0xbf, 0xa, 0x87, 0xc3, 0xad, 0x7d, 0x7d, 0x7d, 0x7f, 0x23, 0x84, 0x78, 0x8c, 0x31, 0xaf, 0x55, 0x0, 0xc6, 0xc7, 0x14, 0x1e, 0x8f, 0xc7, 0xbf, 0x38, 0x3c, 0x3c, 0x6c, 0x9b, 0x9f, 0x9f, 0x6f, 0xb8, 0x82, 0x9b, 0xee, 0xe8, 0xe8, 0xf8, 0x12, 0x0, 0xbe, 0xd3, 0x2a, 0x8, 0xfc, 0x50, 0xd1, 0xf9, 0x7c, 0x9e, 0x8a, 0x46, 0xa3, 0x5f, 0x9d, 0x9e, 0x9e, 0x7e, 0xb2, 0xb0, 0xb0, 0x60, 0xe5, 0x79, 0x1e, 0xf1, 0xfc, 0x7f, 0x3a, 0x9, 0x21, 0x88, 0x10, 0x82, 0x26, 0x26, 0x26, 0xde, 0x77, 0x75, 0x75, 0x85, 0x59, 0x96, 0xfd, 0x5e, 0x6b, 0x20, 0xf0, 0x7d, 0x85, 0x4b, 0x92, 0xf4, 0xfa, 0xe0, 0xe0, 0xe0, 0xd3, 0xb9, 0xb9, 0xb9, 0x46, 0x49, 0x92, 0xea, 0x6f, 0xa, 0xbf, 0x7d, 0x8, 0x21, 0x68, 0x70, 0x70, 0xb0, 0x38, 0x39, 0x39, 0x79, 0xd6, 0xd9, 0xd9, 0xb9, 0xcf, 0x30, 0xcc, 0xa2, 0xd6, 0xad, 0x21, 0x2b, 0x1c, 0x0, 0x38, 0x41, 0x10, 0xfc, 0xdb, 0xdb, 0xdb, 0x27, 0x1e, 0x8f, 0x27, 0x4b, 0x8, 0x1, 0x84, 0x90, 0xea, 0xf, 0x21, 0x4, 0x3c, 0x1e, 0x4f, 0x76, 0x67, 0x67, 0x67, 0x3f, 0x9f, 0xcf, 0xff, 0x7c, 0x5, 0xf3, 0xd9, 0x0, 0xe0, 0x2, 0x81, 0xc0, 0xa9, 0xdb, 0xed, 0x2e, 0x94, 0x2b, 0x5c, 0xe, 0xc4, 0xca, 0xca, 0x8a, 0x18, 0x8d, 0x46, 0x3, 0x0, 0xc0, 0x69, 0x1e, 0x4, 0x0, 0x90, 0x48, 0x24, 0x12, 0xe4, 0x38, 0xee, 0x41, 0xc2, 0x6f, 0x43, 0xe0, 0x38, 0xe, 0xfc, 0x7e, 0xbf, 0x10, 0x8b, 0xc5, 0xd6, 0x35, 0xd, 0x22, 0x9b, 0xcd, 0x7a, 0x96, 0x97, 0x97, 0x33, 0xf, 0xad, 0x7c, 0x29, 0x10, 0x9b, 0x9b, 0x9b, 0xef, 0x2e, 0x2e, 0x2e, 0x7e, 0xd5, 0x1c, 0x8, 0x0, 0x20, 0xe1, 0x70, 0x38, 0xfc, 0x98, 0xd5, 0x57, 0x2, 0xe1, 0x76, 0xbb, 0xf3, 0xa1, 0x50, 0xe8, 0x38, 0x9b, 0xcd, 0xfe, 0xa2, 0x9, 0x8, 0x0, 0x40, 0x2e, 0x2f, 0x2f, 0x7d, 0x4b, 0x4b, 0x4b, 0xb9, 0x4a, 0x54, 0x5f, 0x9, 0xc4, 0xd2, 0xd2, 0x92, 0xb4, 0xb7, 0xb7, 0xf7, 0x36, 0x97, 0xcb, 0x4d, 0x3d, 0x29, 0x8, 0x0, 0xe0, 0x42, 0xa1, 0xd0, 0x71, 0xb5, 0xc4, 0xdf, 0xb6, 0xc5, 0x93, 0xe, 0x4a, 0x0, 0x20, 0xa9, 0x54, 0xea, 0x37, 0xb7, 0xdb, 0x5d, 0xa8, 0xa6, 0x78, 0x39, 0x10, 0x6b, 0x6b, 0x6b, 0xf1, 0x64, 0x32, 0xb9, 0x5a, 0x55, 0x10, 0x0, 0xc0, 0x6d, 0x6c, 0x6c, 0x9c, 0x57, 0xbb, 0xfa, 0x25, 0x40, 0x14, 0x3, 0x81, 0x40, 0x34, 0x93, 0xc9, 0x2c, 0x57, 0x1c, 0x4, 0x0, 0x90, 0x58, 0x2c, 0xb6, 0x5e, 0xe9, 0xc1, 0x77, 0x1f, 0x10, 0x53, 0x53, 0x53, 0x52, 0xc5, 0x83, 0x14, 0x0, 0x70, 0x7e, 0xbf, 0x5f, 0xd0, 0x42, 0xf5, 0x95, 0x40, 0xf8, 0x7c, 0xbe, 0xcb, 0xa3, 0xa3, 0xa3, 0x3f, 0x1e, 0xbd, 0x1b, 0x0, 0x80, 0x1c, 0x1f, 0x1f, 0x87, 0xb4, 0x56, 0xfd, 0xaa, 0x5, 0x29, 0x51, 0x14, 0xbf, 0xf5, 0xf9, 0x7c, 0x97, 0x5a, 0xad, 0xbe, 0x12, 0x88, 0xf5, 0xf5, 0xf5, 0xd8, 0x83, 0x83, 0x54, 0xb5, 0x42, 0x8f, 0x66, 0x83, 0x94, 0xd6, 0xbd, 0x5f, 0xce, 0x7c, 0x38, 0x3c, 0x3c, 0xfc, 0xb3, 0x50, 0x28, 0xb8, 0xcb, 0x2, 0x1, 0x0, 0xdc, 0xf4, 0xf4, 0xf4, 0xfe, 0x73, 0x15, 0x2f, 0x17, 0xa4, 0x22, 0x91, 0x48, 0x50, 0xb5, 0x2d, 0x0, 0x80, 0x9b, 0x99, 0x99, 0x79, 0xfb, 0xdc, 0x1, 0xc8, 0x5, 0xa9, 0x44, 0x22, 0xf1, 0xfb, 0x9d, 0x10, 0x0, 0x80, 0x9b, 0x9d, 0x9d, 0xd, 0xea, 0x5, 0xc0, 0xad, 0xfd, 0x43, 0x1a, 0x0, 0xb8, 0xdb, 0x9a, 0xa9, 0x8f, 0xb6, 0xa4, 0x46, 0xa3, 0xa4, 0xb7, 0xd5, 0x37, 0xcf, 0xf3, 0x68, 0x75, 0x75, 0xf5, 0x4c, 0xee, 0x99, 0x1c, 0x80, 0x9c, 0x1e, 0xf7, 0xff, 0x16, 0x8b, 0x45, 0x50, 0x5, 0xa0, 0xb7, 0xb7, 0xb7, 0x85, 0x10, 0xa2, 0x2b, 0xf1, 0x84, 0x10, 0xd4, 0xdf, 0xdf, 0x6f, 0x57, 0x3, 0x80, 0x37, 0x18, 0xc, 0x5, 0x3d, 0x2, 0xa0, 0x69, 0x3a, 0x8b, 0x10, 0xe2, 0x4b, 0x2, 0xc0, 0x18, 0xf3, 0xc1, 0x60, 0x70, 0x47, 0x8f, 0x16, 0x38, 0x3a, 0x3a, 0x5a, 0x93, 0x5b, 0xc3, 0x7f, 0x64, 0x81, 0xba, 0xba, 0x3a, 0x49, 0x8f, 0x0, 0x1a, 0x1a, 0x1a, 0xd4, 0xcd, 0x0, 0x93, 0xc9, 0xa4, 0xcb, 0x21, 0xe8, 0x74, 0x3a, 0xd5, 0x1, 0xa0, 0x69, 0x5a, 0x77, 0x1d, 0x80, 0x31, 0x2e, 0x38, 0x9d, 0x4e, 0xb1, 0x66, 0x1, 0x30, 0xc, 0x23, 0x28, 0x3d, 0x93, 0x9b, 0x1, 0xb9, 0x9a, 0x6, 0x60, 0x36, 0x9b, 0x75, 0xd7, 0x1, 0x4a, 0x21, 0xa8, 0x26, 0x0, 0x94, 0xa, 0x41, 0xb2, 0x0, 0x18, 0x86, 0xc9, 0xe9, 0xd, 0x80, 0x52, 0x8, 0x92, 0x5, 0x60, 0xb1, 0x58, 0x74, 0x67, 0x1, 0xa5, 0x10, 0xa4, 0x4, 0x40, 0x77, 0x43, 0xd0, 0xe1, 0x70, 0xa8, 0x9f, 0x1, 0x14, 0x45, 0x1, 0x45, 0x51, 0x79, 0x3d, 0x1, 0x68, 0x6e, 0x6e, 0x4e, 0xaa, 0x6, 0x80, 0x10, 0x42, 0x6, 0x83, 0x41, 0x37, 0x36, 0x28, 0x15, 0x82, 0x6a, 0x2, 0x0, 0x4d, 0xd3, 0xa9, 0x52, 0xcf, 0x95, 0x0, 0xe8, 0x66, 0xe, 0x98, 0xcd, 0x66, 0xa1, 0x6c, 0x0, 0x7a, 0x5a, 0x8b, 0x59, 0x2c, 0x96, 0x64, 0xcd, 0x2, 0xb8, 0x2b, 0x4, 0xe9, 0xde, 0x2, 0x77, 0x85, 0xa0, 0x9a, 0xb0, 0x40, 0xa9, 0x10, 0xa4, 0x8, 0xc0, 0x64, 0x32, 0xe9, 0x6, 0x40, 0xa9, 0x10, 0x54, 0xaa, 0x3, 0x74, 0xf3, 0x16, 0x70, 0xb9, 0x5c, 0xe5, 0x3, 0xe8, 0xe9, 0xe9, 0x69, 0xd5, 0xc3, 0x66, 0x18, 0x63, 0x5c, 0x68, 0x6a, 0x6a, 0x12, 0xcb, 0x5, 0xa0, 0x9b, 0xd5, 0x38, 0x4d, 0xd3, 0x29, 0x8a, 0xa2, 0xa0, 0x2c, 0x0, 0x18, 0x63, 0x3e, 0x14, 0xa, 0xfd, 0x55, 0xb, 0x21, 0x48, 0xd1, 0x2, 0x7a, 0x59, 0x8d, 0xdf, 0x1b, 0x80, 0x1e, 0x56, 0xe3, 0x84, 0x10, 0x34, 0x30, 0x30, 0x60, 0xbb, 0xeb, 0x77, 0x46, 0x5, 0xef, 0x48, 0xcf, 0x4d, 0xec, 0x8d, 0x99, 0x5, 0xf5, 0xf5, 0xf5, 0xef, 0x46, 0x47, 0x47, 0xb, 0x2e, 0x97, 0xeb, 0xbc, 0x54, 0x8, 0x52, 0x4, 0xc0, 0x30, 0x8c, 0xf4, 0x5c, 0x4, 0x9b, 0x4c, 0xa6, 0xf4, 0xf8, 0xf8, 0xb8, 0xc8, 0xb2, 0x6c, 0x32, 0x9d, 0x4e, 0xff, 0xd4, 0xdd, 0xdd, 0x7d, 0x66, 0x34, 0x1a, 0x8b, 0xd7, 0x3, 0xfd, 0xae, 0x5b, 0x29, 0xb2, 0x57, 0x66, 0xb6, 0xb6, 0xb6, 0xde, 0xc4, 0xe3, 0xf1, 0x6f, 0xae, 0xaf, 0xc1, 0x28, 0x5d, 0x85, 0x79, 0x2, 0xc1, 0x60, 0xb5, 0x5a, 0xa3, 0xa3, 0xa3, 0xa3, 0x45, 0xab, 0xd5, 0x9a, 0x2a, 0x16, 0x8b, 0x8b, 0x6d, 0x6d, 0x6d, 0xef, 0xd5, 0x8a, 0x55, 0xd, 0x20, 0x91, 0x48, 0xbc, 0x3e, 0x38, 0x38, 0xf8, 0xda, 0x6e, 0xb7, 0xf7, 0x5f, 0x5c, 0x5c, 0xd4, 0x7b, 0xbd, 0xde, 0xbc, 0x20, 0x8, 0xcd, 0x85, 0x42, 0x81, 0xfe, 0xf0, 0xae, 0xac, 0x10, 0x98, 0x9b, 0xd5, 0xc5, 0x18, 0x17, 0x59, 0x96, 0x3d, 0x1d, 0x19, 0x19, 0x1, 0x96, 0x65, 0x5, 0x8a, 0xa2, 0x7e, 0x6c, 0x69, 0x69, 0x49, 0x3d, 0x44, 0xb0, 0x2a, 0x0, 0x1f, 0xcc, 0x74, 0x75, 0x41, 0xea, 0xfa, 0x7b, 0x32, 0x99, 0x64, 0x76, 0x77, 0x77, 0x5d, 0xe, 0x87, 0xa3, 0x5f, 0x14, 0xc5, 0x57, 0x57, 0x60, 0x5a, 0x8b, 0xc5, 0xa2, 0xf1, 0xbe, 0x50, 0x6e, 0xa, 0x66, 0x18, 0x26, 0x31, 0x36, 0x36, 0x96, 0x65, 0x59, 0x36, 0x29, 0x49, 0x92, 0xb7, 0xbd, 0xbd, 0xfd, 0x9f, 0x72, 0xda, 0xf9, 0xd1, 0x1, 0xa8, 0x1, 0x93, 0xcf, 0xe7, 0xa9, 0x93, 0x93, 0x13, 0x1b, 0x4d, 0xd3, 0x9f, 0xb, 0x82, 0x60, 0xf5, 0x7a, 0xbd, 0xd9, 0x54, 0x2a, 0xe5, 0xcc, 0x64, 0x32, 0xe, 0xb9, 0x6e, 0xb9, 0x16, 0x8c, 0x31, 0x2e, 0xda, 0x6c, 0xb6, 0xc8, 0xd0, 0xd0, 0x10, 0x65, 0xb3, 0xd9, 0x92, 0x95, 0xa8, 0x6e, 0xc5, 0x0, 0xa8, 0xe9, 0x96, 0x68, 0x34, 0x6a, 0xdd, 0xdf, 0xdf, 0x6f, 0x76, 0xb9, 0x5c, 0x9f, 0x89, 0xa2, 0x58, 0xbf, 0xb8, 0xb8, 0x8, 0x26, 0x93, 0x29, 0x3b, 0x3c, 0x3c, 0x8c, 0xed, 0x76, 0x7b, 0xd2, 0x68, 0x34, 0xfe, 0xd0, 0xd8, 0xd8, 0x98, 0xae, 0xb6, 0xe0, 0x8a, 0x1, 0x50, 0xb, 0xe6, 0xa9, 0x5, 0xbf, 0x9c, 0x97, 0xf3, 0xff, 0xf3, 0x2f, 0x6a, 0x82, 0x7f, 0xf6, 0x4e, 0xca, 0x1b, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + +class TestPhysics2DMainLoop : public MainLoop { + GDCLASS(TestPhysics2DMainLoop, MainLoop); + + RID circle_img; + RID circle_shape; + RID space; + RID canvas; + RID ray; + RID ray_query; + Transform2D view_xform; + + Vector2 ray_from, ray_to; + + struct BodyShapeData { + RID image; + RID shape; + }; + + BodyShapeData body_shape_data[8]; + + void _create_body_shape_data() { + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + + // SEGMENT + + { + Vector pixels; + pixels.resize(32 * 2 * 2); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 32; j++) { + pixels.set(i * 32 * 2 + j * 2 + 0, (j == 0) ? 255 : 0); + pixels.set(i * 32 * 2 + j * 2 + 1, 255); + } + } + + Ref image = memnew(Image(32, 2, 0, Image::FORMAT_LA8, pixels)); + + body_shape_data[PhysicsServer2D::SHAPE_SEGMENT].image = vs->texture_2d_create(image); + + RID segment_shape = ps->segment_shape_create(); + Rect2 sg(Point2(-16, 0), Point2(16, 0)); + ps->shape_set_data(segment_shape, sg); + + body_shape_data[PhysicsServer2D::SHAPE_SEGMENT].shape = segment_shape; + } + // CIRCLE + + { + Vector pixels; + pixels.resize(32 * 32 * 2); + for (int i = 0; i < 32; i++) { + for (int j = 0; j < 32; j++) { + bool black = Vector2(i - 16, j - 16).length_squared() < 16 * 16; + + pixels.set(i * 32 * 2 + j * 2 + 0, (i == 16 || j == 16) ? 255 : 0); + pixels.set(i * 32 * 2 + j * 2 + 1, black ? 255 : 0); + } + } + + Ref image = memnew(Image(32, 32, 0, Image::FORMAT_LA8, pixels)); + + body_shape_data[PhysicsServer2D::SHAPE_CIRCLE].image = vs->texture_2d_create(image); + + RID circle_shape = ps->circle_shape_create(); + ps->shape_set_data(circle_shape, 16); + + body_shape_data[PhysicsServer2D::SHAPE_CIRCLE].shape = circle_shape; + } + + // BOX + + { + Vector pixels; + pixels.resize(32 * 32 * 2); + for (int i = 0; i < 32; i++) { + for (int j = 0; j < 32; j++) { + bool black = i > 0 && i < 31 && j > 0 && j < 31; + + pixels.set(i * 32 * 2 + j * 2 + 0, black ? 0 : 255); + pixels.set(i * 32 * 2 + j * 2 + 1, 255); + } + } + + Ref image = memnew(Image(32, 32, 0, Image::FORMAT_LA8, pixels)); + + body_shape_data[PhysicsServer2D::SHAPE_RECTANGLE].image = vs->texture_2d_create(image); + + RID rectangle_shape = ps->rectangle_shape_create(); + ps->shape_set_data(rectangle_shape, Vector2(16, 16)); + + body_shape_data[PhysicsServer2D::SHAPE_RECTANGLE].shape = rectangle_shape; + } + + // CAPSULE + + { + Vector pixels; + pixels.resize(32 * 64 * 2); + for (int i = 0; i < 64; i++) { + for (int j = 0; j < 32; j++) { + int si = i > 48 ? i - 32 : (i < 16 ? i : 16); + bool black = Vector2(si - 16, j - 16).length_squared() < 16 * 16; + + pixels.set(i * 32 * 2 + j * 2 + 0, (i == 16 || j == 16 || i == 48) ? 255 : 0); + pixels.set(i * 32 * 2 + j * 2 + 1, black ? 255 : 0); + } + } + + Ref image = memnew(Image(32, 64, 0, Image::FORMAT_LA8, pixels)); + + body_shape_data[PhysicsServer2D::SHAPE_CAPSULE].image = vs->texture_2d_create(image); + + RID capsule_shape = ps->capsule_shape_create(); + ps->shape_set_data(capsule_shape, Vector2(16, 32)); + + body_shape_data[PhysicsServer2D::SHAPE_CAPSULE].shape = capsule_shape; + } + + // CONVEX + + { + Ref image = memnew(Image(convex_png)); + + body_shape_data[PhysicsServer2D::SHAPE_CONVEX_POLYGON].image = vs->texture_2d_create(image); + + RID convex_polygon_shape = ps->convex_polygon_shape_create(); + + Vector arr; + Point2 sb(32, 32); + arr.push_back(Point2(20, 3) - sb); + arr.push_back(Point2(58, 23) - sb); + arr.push_back(Point2(55, 54) - sb); + arr.push_back(Point2(27, 60) - sb); + arr.push_back(Point2(5, 56) - sb); + arr.push_back(Point2(4, 20) - sb); + arr.push_back(Point2(11, 7) - sb); + ps->shape_set_data(convex_polygon_shape, arr); + + body_shape_data[PhysicsServer2D::SHAPE_CONVEX_POLYGON].shape = convex_polygon_shape; + } + } + + void _do_ray_query() { + /* + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + ps->query_intersection_segment(ray_query,ray_from,ray_to); + */ + } + +protected: + void input_event(const Ref &p_event) { + Ref mb = p_event; + + if (mb.is_valid()) { + if (mb->is_pressed()) { + Point2 p = mb->get_position(); + + if (mb->get_button_index() == 1) { + ray_to = p; + _do_ray_query(); + } else if (mb->get_button_index() == 2) { + ray_from = p; + _do_ray_query(); + } + } + } + + Ref mm = p_event; + + if (mm.is_valid()) { + Point2 p = mm->get_position(); + + if (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) { + ray_to = p; + _do_ray_query(); + } else if (mm->get_button_mask() & MOUSE_BUTTON_MASK_RIGHT) { + ray_from = p; + _do_ray_query(); + } + } + } + + RID _add_body(PhysicsServer2D::ShapeType p_shape, const Transform2D &p_xform) { + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + + RID body = ps->body_create(); + ps->body_add_shape(body, body_shape_data[p_shape].shape); + ps->body_set_space(body, space); + ps->body_set_continuous_collision_detection_mode(body, PhysicsServer2D::CCD_MODE_CAST_SHAPE); + ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, p_xform); + + //print_line("add body with xform: "+p_xform); + RID sprite = vs->canvas_item_create(); + vs->canvas_item_set_parent(sprite, canvas); + vs->canvas_item_set_transform(sprite, p_xform); + Size2 imgsize(5, 5); //vs->texture_get_width(body_shape_data[p_shape].image), vs->texture_get_height(body_shape_data[p_shape].image)); + vs->canvas_item_add_texture_rect(sprite, Rect2(-imgsize / 2.0, imgsize), body_shape_data[p_shape].image); + + ps->body_set_force_integration_callback(body, callable_mp(this, &TestPhysics2DMainLoop::_body_moved), sprite); + + return body; + } + + void _add_world_boundary(const Vector2 &p_normal, real_t p_d) { + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + + Array arr; + arr.push_back(p_normal); + arr.push_back(p_d); + + RID world_boundary = ps->world_boundary_shape_create(); + ps->shape_set_data(world_boundary, arr); + + RID plane_body = ps->body_create(); + ps->body_set_mode(plane_body, PhysicsServer2D::BODY_MODE_STATIC); + ps->body_set_space(plane_body, space); + ps->body_add_shape(plane_body, world_boundary); + } + + void _add_concave(const Vector &p_points, const Transform2D &p_xform = Transform2D()) { + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + RenderingServer *vs = RenderingServer::get_singleton(); + + RID concave = ps->concave_polygon_shape_create(); + ps->shape_set_data(concave, p_points); + RID body = ps->body_create(); + ps->body_set_mode(body, PhysicsServer2D::BODY_MODE_STATIC); + ps->body_set_space(body, space); + ps->body_add_shape(body, concave); + ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, p_xform); + + RID sprite = vs->canvas_item_create(); + vs->canvas_item_set_parent(sprite, canvas); + vs->canvas_item_set_transform(sprite, p_xform); + for (int i = 0; i < p_points.size(); i += 2) { + vs->canvas_item_add_line(sprite, p_points[i], p_points[i + 1], Color(0, 0, 0), 2); + } + } + + void _body_moved(Object *p_state, RID p_sprite) { + PhysicsDirectBodyState2D *state = (PhysicsDirectBodyState2D *)p_state; + RenderingServer::get_singleton()->canvas_item_set_transform(p_sprite, state->get_transform()); + } + + void _ray_query_callback(const RID &p_rid, ObjectID p_id, int p_shape, const Vector2 &p_point, const Vector2 &p_normal) { + Vector2 ray_end; + + if (p_rid.is_valid()) { + ray_end = p_point; + } else { + ray_end = ray_to; + } + + RenderingServer *vs = RenderingServer::get_singleton(); + + vs->canvas_item_clear(ray); + vs->canvas_item_add_line(ray, ray_from, ray_end, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2); + if (p_rid.is_valid()) { + vs->canvas_item_add_line(ray, ray_end, ray_end + p_normal * 20, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2); + } + } + + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("_ray_query_callback"), &TestPhysics2DMainLoop::_ray_query_callback); + } + +public: + virtual void initialize() override { + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + + space = ps->space_create(); + ps->space_set_active(space, true); + ps->set_active(true); + ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1)); + ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, 980); + + { + RID vp = vs->viewport_create(); + canvas = vs->canvas_create(); + + Size2i screen_size = DisplayServer::get_singleton()->window_get_size(); + vs->viewport_attach_canvas(vp, canvas); + vs->viewport_set_size(vp, screen_size.x, screen_size.y); + vs->viewport_attach_to_screen(vp, Rect2(Vector2(), screen_size)); + vs->viewport_set_active(vp, true); + + Transform2D smaller; + //smaller.scale(Vector2(0.6,0.6)); + //smaller.elements[2]=Vector2(100,0); + + //view_xform = smaller; + vs->viewport_set_canvas_transform(vp, canvas, view_xform); + } + + ray = vs->canvas_item_create(); + vs->canvas_item_set_parent(ray, canvas); + //ray_query = ps->query_create(this,"_ray_query_callback",Variant()); + //ps->query_intersection(ray_query,space); + + _create_body_shape_data(); + + for (int i = 0; i < 32; i++) { + PhysicsServer2D::ShapeType types[4] = { + PhysicsServer2D::SHAPE_CIRCLE, + PhysicsServer2D::SHAPE_CAPSULE, + PhysicsServer2D::SHAPE_RECTANGLE, + PhysicsServer2D::SHAPE_CONVEX_POLYGON, + + }; + + PhysicsServer2D::ShapeType type = types[i % 4]; + //type=PhysicsServer2D::SHAPE_SEGMENT; + _add_body(type, Transform2D(i * 0.8, Point2(152 + i * 40, 100 - 40 * i))); + /* + if (i==0) + ps->body_set_mode(b,PhysicsServer2D::BODY_MODE_STATIC); + */ + } + + //RID b= _add_body(PhysicsServer2D::SHAPE_CIRCLE,Transform2D(0,Point2(101,140))); + //ps->body_set_mode(b,PhysicsServer2D::BODY_MODE_STATIC); + + Point2 prev; + + Vector parr; + for (int i = 0; i < 30; i++) { + Point2 p(i * 60, Math::randf() * 70 + 340); + if (i > 0) { + parr.push_back(prev); + parr.push_back(p); + } + prev = p; + } + + _add_concave(parr); + //_add_world_boundary(Vector2(0.0,-1).normalized(),-300); + //_add_world_boundary(Vector2(1,0).normalized(),50); + //_add_world_boundary(Vector2(-1,0).normalized(),-600); + } + + virtual bool process(double p_time) override { + return false; + } + virtual void finalize() override { + } + + TestPhysics2DMainLoop() {} +}; + +namespace TestPhysics2D { + +MainLoop *test() { + return memnew(TestPhysics2DMainLoop); +} +} // namespace TestPhysics2D diff --git a/tests/servers/test_physics_2d.h b/tests/servers/test_physics_2d.h new file mode 100644 index 0000000000..2ae1053a03 --- /dev/null +++ b/tests/servers/test_physics_2d.h @@ -0,0 +1,41 @@ +/*************************************************************************/ +/* test_physics_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_PHYSICS_2D_H +#define TEST_PHYSICS_2D_H + +class MainLoop; + +namespace TestPhysics2D { + +MainLoop *test(); +} + +#endif // TEST_PHYSICS_2D_H diff --git a/tests/servers/test_physics_3d.cpp b/tests/servers/test_physics_3d.cpp new file mode 100644 index 0000000000..4e483d628d --- /dev/null +++ b/tests/servers/test_physics_3d.cpp @@ -0,0 +1,410 @@ +/*************************************************************************/ +/* test_physics_3d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "test_physics_3d.h" + +#include "core/math/convex_hull.h" +#include "core/math/geometry_3d.h" +#include "core/os/main_loop.h" +#include "servers/physics_server_3d.h" +#include "servers/rendering_server.h" + +class TestPhysics3DMainLoop : public MainLoop { + GDCLASS(TestPhysics3DMainLoop, MainLoop); + + enum { + LINK_COUNT = 20, + }; + + RID test_cube; + + RID plane; + RID sphere; + RID light; + RID camera; + RID mover; + RID scenario; + RID space; + + RID character; + + real_t ofs_x, ofs_y; + + Point2 joy_direction; + + List bodies; + Map type_shape_map; + Map type_mesh_map; + + void body_changed_transform(Object *p_state, RID p_visual_instance) { + PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; + RenderingServer *vs = RenderingServer::get_singleton(); + Transform3D t = state->get_transform(); + vs->instance_set_transform(p_visual_instance, t); + } + + bool quit; + +protected: + RID create_body(PhysicsServer3D::ShapeType p_shape, PhysicsServer3D::BodyMode p_body, const Transform3D p_location, bool p_active_default = true, const Transform3D &p_shape_xform = Transform3D()) { + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + + RID mesh_instance = vs->instance_create2(type_mesh_map[p_shape], scenario); + RID body = ps->body_create(); + ps->body_set_mode(body, p_body); + ps->body_set_state(body, PhysicsServer3D::BODY_STATE_SLEEPING, !p_active_default); + ps->body_set_space(body, space); + ps->body_set_param(body, PhysicsServer3D::BODY_PARAM_BOUNCE, 0.0); + //todo set space + ps->body_add_shape(body, type_shape_map[p_shape]); + ps->body_set_force_integration_callback(body, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance); + + ps->body_set_state(body, PhysicsServer3D::BODY_STATE_TRANSFORM, p_location); + bodies.push_back(body); + + if (p_body == PhysicsServer3D::BODY_MODE_STATIC) { + vs->instance_set_transform(mesh_instance, p_location); + } + return body; + } + + RID create_world_boundary(const Plane &p_plane) { + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + + RID world_boundary_shape = ps->shape_create(PhysicsServer3D::SHAPE_WORLD_BOUNDARY); + ps->shape_set_data(world_boundary_shape, p_plane); + + RID b = ps->body_create(); + ps->body_set_mode(b, PhysicsServer3D::BODY_MODE_STATIC); + + ps->body_set_space(b, space); + ps->body_add_shape(b, world_boundary_shape); + return b; + } + + void configure_body(RID p_body, real_t p_mass, real_t p_friction, real_t p_bounce) { + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_MASS, p_mass); + ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_FRICTION, p_friction); + ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_BOUNCE, p_bounce); + } + + void initialize_shapes() { + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + + /* SPHERE SHAPE */ + RID sphere_mesh = vs->make_sphere_mesh(10, 20, 0.5); + type_mesh_map[PhysicsServer3D::SHAPE_SPHERE] = sphere_mesh; + + RID sphere_shape = ps->shape_create(PhysicsServer3D::SHAPE_SPHERE); + ps->shape_set_data(sphere_shape, 0.5); + type_shape_map[PhysicsServer3D::SHAPE_SPHERE] = sphere_shape; + + /* BOX SHAPE */ + + Vector box_planes = Geometry3D::build_box_planes(Vector3(0.5, 0.5, 0.5)); + RID box_mesh = vs->mesh_create(); + Geometry3D::MeshData box_data = Geometry3D::build_convex_mesh(box_planes); + vs->mesh_add_surface_from_mesh_data(box_mesh, box_data); + type_mesh_map[PhysicsServer3D::SHAPE_BOX] = box_mesh; + + RID box_shape = ps->shape_create(PhysicsServer3D::SHAPE_BOX); + ps->shape_set_data(box_shape, Vector3(0.5, 0.5, 0.5)); + type_shape_map[PhysicsServer3D::SHAPE_BOX] = box_shape; + + /* CAPSULE SHAPE */ + + Vector capsule_planes = Geometry3D::build_capsule_planes(0.5, 0.7, 12, Vector3::AXIS_Z); + + RID capsule_mesh = vs->mesh_create(); + Geometry3D::MeshData capsule_data = Geometry3D::build_convex_mesh(capsule_planes); + vs->mesh_add_surface_from_mesh_data(capsule_mesh, capsule_data); + + type_mesh_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_mesh; + + RID capsule_shape = ps->shape_create(PhysicsServer3D::SHAPE_CAPSULE); + Dictionary capsule_params; + capsule_params["radius"] = 0.5; + capsule_params["height"] = 1.4; + ps->shape_set_data(capsule_shape, capsule_params); + type_shape_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_shape; + + /* CONVEX SHAPE */ + + Vector convex_planes = Geometry3D::build_cylinder_planes(0.5, 0.7, 5, Vector3::AXIS_Z); + + RID convex_mesh = vs->mesh_create(); + Geometry3D::MeshData convex_data = Geometry3D::build_convex_mesh(convex_planes); + ConvexHullComputer::convex_hull(convex_data.vertices, convex_data); + vs->mesh_add_surface_from_mesh_data(convex_mesh, convex_data); + + type_mesh_map[PhysicsServer3D::SHAPE_CONVEX_POLYGON] = convex_mesh; + + RID convex_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON); + ps->shape_set_data(convex_shape, convex_data.vertices); + type_shape_map[PhysicsServer3D::SHAPE_CONVEX_POLYGON] = convex_shape; + } + + void make_trimesh(Vector p_faces, const Transform3D &p_xform = Transform3D()) { + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + RID trimesh_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON); + Dictionary trimesh_params; + trimesh_params["faces"] = p_faces; + trimesh_params["backface_collision"] = false; + ps->shape_set_data(trimesh_shape, trimesh_params); + Vector normals; // for drawing + for (int i = 0; i < p_faces.size() / 3; i++) { + Plane p(p_faces[i * 3 + 0], p_faces[i * 3 + 1], p_faces[i * 3 + 2]); + normals.push_back(p.normal); + normals.push_back(p.normal); + normals.push_back(p.normal); + } + + RID trimesh_mesh = vs->mesh_create(); + Array d; + d.resize(RS::ARRAY_MAX); + d[RS::ARRAY_VERTEX] = p_faces; + d[RS::ARRAY_NORMAL] = normals; + vs->mesh_add_surface_from_arrays(trimesh_mesh, RS::PRIMITIVE_TRIANGLES, d); + + RID triins = vs->instance_create2(trimesh_mesh, scenario); + + RID tribody = ps->body_create(); + ps->body_set_mode(tribody, PhysicsServer3D::BODY_MODE_STATIC); + ps->body_set_space(tribody, space); + //todo set space + ps->body_add_shape(tribody, trimesh_shape); + Transform3D tritrans = p_xform; + ps->body_set_state(tribody, PhysicsServer3D::BODY_STATE_TRANSFORM, tritrans); + vs->instance_set_transform(triins, tritrans); + } + + void make_grid(int p_width, int p_height, real_t p_cellsize, real_t p_cellheight, const Transform3D &p_xform = Transform3D()) { + Vector> grid; + + grid.resize(p_width); + + for (int i = 0; i < p_width; i++) { + grid.write[i].resize(p_height); + + for (int j = 0; j < p_height; j++) { + grid.write[i].write[j] = 1.0 + Math::random(-p_cellheight, p_cellheight); + } + } + + Vector faces; + + for (int i = 1; i < p_width; i++) { + for (int j = 1; j < p_height; j++) { +#define MAKE_VERTEX(m_x, m_z) \ + faces.push_back(Vector3((m_x - p_width / 2) * p_cellsize, grid[m_x][m_z], (m_z - p_height / 2) * p_cellsize)) + + MAKE_VERTEX(i, j - 1); + MAKE_VERTEX(i, j); + MAKE_VERTEX(i - 1, j); + + MAKE_VERTEX(i - 1, j - 1); + MAKE_VERTEX(i, j - 1); + MAKE_VERTEX(i - 1, j); + } + } + + make_trimesh(faces, p_xform); + } + +public: + virtual void input_event(const Ref &p_event) { + Ref mm = p_event; + if (mm.is_valid() && mm->get_button_mask() & 4) { + ofs_y -= mm->get_relative().y / 200.0; + ofs_x += mm->get_relative().x / 200.0; + } + + if (mm.is_valid() && mm->get_button_mask() & 1) { + real_t y = -mm->get_relative().y / 20.0; + real_t x = mm->get_relative().x / 20.0; + + if (mover.is_valid()) { + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + Transform3D t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); + t.origin += Vector3(x, y, 0); + + ps->body_set_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM, t); + } + } + } + + virtual void request_quit() { + quit = true; + } + virtual void initialize() override { + ofs_x = ofs_y = 0; + initialize_shapes(); + + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + space = ps->space_create(); + ps->space_set_active(space, true); + + RenderingServer *vs = RenderingServer::get_singleton(); + + /* LIGHT */ + RID lightaux = vs->directional_light_create(); + scenario = vs->scenario_create(); + vs->light_set_shadow(lightaux, true); + light = vs->instance_create2(lightaux, scenario); + Transform3D t; + t.rotate(Vector3(1.0, 0, 0), 0.6); + vs->instance_set_transform(light, t); + + /* CAMERA */ + + camera = vs->camera_create(); + + RID viewport = vs->viewport_create(); + Size2i screen_size = DisplayServer::get_singleton()->window_get_size(); + vs->viewport_set_size(viewport, screen_size.x, screen_size.y); + vs->viewport_attach_to_screen(viewport, Rect2(Vector2(), screen_size)); + vs->viewport_set_active(viewport, true); + vs->viewport_attach_camera(viewport, camera); + vs->viewport_set_scenario(viewport, scenario); + + vs->camera_set_perspective(camera, 60, 0.1, 40.0); + vs->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 9, 12))); + + Transform3D gxf; + gxf.basis.scale(Vector3(1.4, 0.4, 1.4)); + gxf.origin = Vector3(-2, 1, -2); + make_grid(5, 5, 2.5, 1, gxf); + test_fall(); + quit = false; + } + virtual bool physics_process(double p_time) override { + if (mover.is_valid()) { + static real_t joy_speed = 10; + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + Transform3D t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); + t.origin += Vector3(joy_speed * joy_direction.x * p_time, -joy_speed * joy_direction.y * p_time, 0); + ps->body_set_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM, t); + }; + + Transform3D cameratr; + cameratr.rotate(Vector3(0, 1, 0), ofs_x); + cameratr.rotate(Vector3(1, 0, 0), -ofs_y); + cameratr.translate(Vector3(0, 2, 8)); + RenderingServer *vs = RenderingServer::get_singleton(); + vs->camera_set_transform(camera, cameratr); + + return quit; + } + virtual void finalize() override { + } + + void test_joint() { + } + + void test_hinge() { + } + + void test_character() { + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + + Vector capsule_planes = Geometry3D::build_capsule_planes(0.5, 1, 12, 5, Vector3::AXIS_Y); + + RID capsule_mesh = vs->mesh_create(); + Geometry3D::MeshData capsule_data = Geometry3D::build_convex_mesh(capsule_planes); + vs->mesh_add_surface_from_mesh_data(capsule_mesh, capsule_data); + type_mesh_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_mesh; + + RID capsule_shape = ps->shape_create(PhysicsServer3D::SHAPE_CAPSULE); + Dictionary capsule_params; + capsule_params["radius"] = 0.5; + capsule_params["height"] = 1; + Transform3D shape_xform; + shape_xform.rotate(Vector3(1, 0, 0), Math_PI / 2.0); + //shape_xform.origin=Vector3(1,1,1); + ps->shape_set_data(capsule_shape, capsule_params); + + RID mesh_instance = vs->instance_create2(capsule_mesh, scenario); + character = ps->body_create(); + ps->body_set_mode(character, PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR); + ps->body_set_space(character, space); + //todo add space + ps->body_add_shape(character, capsule_shape); + ps->body_set_force_integration_callback(character, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance); + + ps->body_set_state(character, PhysicsServer3D::BODY_STATE_TRANSFORM, Transform3D(Basis(), Vector3(-2, 5, -2))); + bodies.push_back(character); + } + + void test_fall() { + for (int i = 0; i < 35; i++) { + static const PhysicsServer3D::ShapeType shape_idx[] = { + PhysicsServer3D::SHAPE_CAPSULE, + PhysicsServer3D::SHAPE_BOX, + PhysicsServer3D::SHAPE_SPHERE, + PhysicsServer3D::SHAPE_CONVEX_POLYGON + }; + + PhysicsServer3D::ShapeType type = shape_idx[i % 4]; + + Transform3D t; + + t.origin = Vector3(0.0 * i, 3.5 + 1.1 * i, 0.7 + 0.0 * i); + t.basis.rotate(Vector3(0.2, -1, 0), Math_PI / 2 * 0.6); + + create_body(type, PhysicsServer3D::BODY_MODE_DYNAMIC, t); + } + + create_world_boundary(Plane(Vector3(0, 1, 0), -1)); + } + + void test_activate() { + create_body(PhysicsServer3D::SHAPE_BOX, PhysicsServer3D::BODY_MODE_DYNAMIC, Transform3D(Basis(), Vector3(0, 2, 0)), true); + create_world_boundary(Plane(Vector3(0, 1, 0), -1)); + } + + virtual bool process(double p_time) override { + return false; + } + + TestPhysics3DMainLoop() { + } +}; + +namespace TestPhysics3D { + +MainLoop *test() { + return memnew(TestPhysics3DMainLoop); +} +} // namespace TestPhysics3D diff --git a/tests/servers/test_physics_3d.h b/tests/servers/test_physics_3d.h new file mode 100644 index 0000000000..b86327cdb4 --- /dev/null +++ b/tests/servers/test_physics_3d.h @@ -0,0 +1,41 @@ +/*************************************************************************/ +/* test_physics_3d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_PHYSICS_H +#define TEST_PHYSICS_H + +class MainLoop; + +namespace TestPhysics3D { + +MainLoop *test(); +} + +#endif diff --git a/tests/servers/test_render.cpp b/tests/servers/test_render.cpp new file mode 100644 index 0000000000..183f049238 --- /dev/null +++ b/tests/servers/test_render.cpp @@ -0,0 +1,232 @@ +/*************************************************************************/ +/* test_render.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "test_render.h" + +#include "core/math/convex_hull.h" +#include "core/os/main_loop.h" +#include "servers/rendering_server.h" + +#define OBJECT_COUNT 50 + +namespace TestRender { + +class TestMainLoop : public MainLoop { + RID test_cube; + RID instance; + RID camera; + RID viewport; + RID light; + RID scenario; + + struct InstanceInfo { + RID instance; + Transform3D base; + Vector3 rot_axis; + }; + + List instances; + + float ofs; + bool quit; + +protected: +public: + virtual void input_event(const Ref &p_event) { + if (p_event->is_pressed()) { + quit = true; + } + } + + virtual void init() { + print_line("INITIALIZING TEST RENDER"); + RenderingServer *vs = RenderingServer::get_singleton(); + test_cube = vs->get_test_cube(); + scenario = vs->scenario_create(); + + Vector vts; + + /* + Vector sp = Geometry3D::build_sphere_planes(2,5,5); + Geometry3D::MeshData md2 = Geometry3D::build_convex_mesh(sp); + vts=md2.vertices; +*/ + /* + + static const int s = 20; + for(int i=0;imesh_create(); + vs->mesh_add_surface_from_mesh_data(test_cube, md); + //vs->scenario_set_debug(scenario,RS::SCENARIO_DEBUG_WIREFRAME); + + /* + RID sm = vs->shader_create(); + //vs->shader_set_fragment_code(sm,"OUT_ALPHA=mod(TIME,1);"); + //vs->shader_set_vertex_code(sm,"OUT_VERTEX=IN_VERTEX*mod(TIME,1);"); + vs->shader_set_fragment_code(sm,"OUT_DIFFUSE=vec3(1,0,1);OUT_GLOW=abs(sin(TIME));"); + RID tcmat = vs->mesh_surface_get_material(test_cube,0); + vs->material_set_shader(tcmat,sm); + */ + + List cmdline = OS::get_singleton()->get_cmdline_args(); + int object_count = OBJECT_COUNT; + if (cmdline.size() > 0 && cmdline[cmdline.size() - 1].to_int()) { + object_count = cmdline[cmdline.size() - 1].to_int(); + }; + + for (int i = 0; i < object_count; i++) { + InstanceInfo ii; + + ii.instance = vs->instance_create2(test_cube, scenario); + + ii.base.translate(Math::random(-20, 20), Math::random(-20, 20), Math::random(-20, 18)); + ii.base.rotate(Vector3(0, 1, 0), Math::randf() * Math_PI); + ii.base.rotate(Vector3(1, 0, 0), Math::randf() * Math_PI); + vs->instance_set_transform(ii.instance, ii.base); + + ii.rot_axis = Vector3(Math::random(-1, 1), Math::random(-1, 1), Math::random(-1, 1)).normalized(); + + instances.push_back(ii); + } + + camera = vs->camera_create(); + + // vs->camera_set_perspective( camera, 60.0,0.1, 100.0 ); + + viewport = vs->viewport_create(); + Size2i screen_size = DisplayServer::get_singleton()->window_get_size(); + vs->viewport_set_size(viewport, screen_size.x, screen_size.y); + vs->viewport_attach_to_screen(viewport, Rect2(Vector2(), screen_size)); + vs->viewport_set_active(viewport, true); + vs->viewport_attach_camera(viewport, camera); + vs->viewport_set_scenario(viewport, scenario); + vs->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 3, 30))); + vs->camera_set_perspective(camera, 60, 0.1, 1000); + + /* + RID lightaux = vs->light_create( RenderingServer::LIGHT_OMNI ); + vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_RADIUS, 80 ); + vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_ATTENUATION, 1 ); + vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_ENERGY, 1.5 ); + light = vs->instance_create( lightaux ); + */ + RID lightaux; + + lightaux = vs->directional_light_create(); + //vs->light_set_color( lightaux, RenderingServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) ); + vs->light_set_color(lightaux, Color(1.0, 1.0, 1.0)); + //vs->light_set_shadow( lightaux, true ); + light = vs->instance_create2(lightaux, scenario); + Transform3D lla; + //lla.set_look_at(Vector3(),Vector3(1, -1, 1)); + lla.basis = Basis::looking_at(Vector3(0.0, -0.836026, -0.548690)); + + vs->instance_set_transform(light, lla); + + lightaux = vs->omni_light_create(); + //vs->light_set_color( lightaux, RenderingServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,1.0) ); + vs->light_set_color(lightaux, Color(1.0, 1.0, 0.0)); + vs->light_set_param(lightaux, RenderingServer::LIGHT_PARAM_RANGE, 4); + vs->light_set_param(lightaux, RenderingServer::LIGHT_PARAM_ENERGY, 8); + //vs->light_set_shadow( lightaux, true ); + //light = vs->instance_create( lightaux ); + + ofs = 0; + quit = false; + } + virtual bool iteration(double p_time) { + RenderingServer *vs = RenderingServer::get_singleton(); + //Transform3D t; + //t.rotate(Vector3(0, 1, 0), ofs); + //t.translate(Vector3(0,0,20 )); + //vs->camera_set_transform(camera, t); + + ofs += p_time * 0.05; + + //return quit; + + for (const InstanceInfo &E : instances) { + Transform3D pre(Basis(E.rot_axis, ofs), Vector3()); + vs->instance_set_transform(E.instance, pre * E.base); + /* + if( !E->next() ) { + vs->free( E.instance ); + instances.erase(E ); + }*/ + } + + return quit; + } + + virtual bool idle(double p_time) { + return quit; + } + + virtual void finish() { + } +}; + +MainLoop *test() { + return memnew(TestMainLoop); +} +} // namespace TestRender diff --git a/tests/servers/test_render.h b/tests/servers/test_render.h new file mode 100644 index 0000000000..1d773cb347 --- /dev/null +++ b/tests/servers/test_render.h @@ -0,0 +1,41 @@ +/*************************************************************************/ +/* test_render.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_RENDER_H +#define TEST_RENDER_H + +class MainLoop; + +namespace TestRender { + +MainLoop *test(); +} + +#endif // TEST_RENDER_H diff --git a/tests/servers/test_shader_lang.cpp b/tests/servers/test_shader_lang.cpp new file mode 100644 index 0000000000..0591bf6adf --- /dev/null +++ b/tests/servers/test_shader_lang.cpp @@ -0,0 +1,360 @@ +/*************************************************************************/ +/* test_shader_lang.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "test_shader_lang.h" + +#include "core/os/main_loop.h" +#include "core/os/os.h" +#include "servers/rendering/shader_language.h" + +typedef ShaderLanguage SL; + +namespace TestShaderLang { + +static String _mktab(int p_level) { + String tb; + for (int i = 0; i < p_level; i++) { + tb += "\t"; + } + + return tb; +} + +static String _typestr(SL::DataType p_type) { + return ShaderLanguage::get_datatype_name(p_type); +} + +static String _prestr(SL::DataPrecision p_pres) { + switch (p_pres) { + case SL::PRECISION_LOWP: + return "lowp "; + case SL::PRECISION_MEDIUMP: + return "mediump "; + case SL::PRECISION_HIGHP: + return "highp "; + case SL::PRECISION_DEFAULT: + return ""; + } + return ""; +} + +static String _opstr(SL::Operator p_op) { + return ShaderLanguage::get_operator_text(p_op); +} + +static String get_constant_text(SL::DataType p_type, const Vector &p_values) { + switch (p_type) { + case SL::TYPE_BOOL: + return p_values[0].boolean ? "true" : "false"; + case SL::TYPE_BVEC2: + return String() + "bvec2(" + (p_values[0].boolean ? "true" : "false") + (p_values[1].boolean ? "true" : "false") + ")"; + case SL::TYPE_BVEC3: + return String() + "bvec3(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + ")"; + case SL::TYPE_BVEC4: + return String() + "bvec4(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + "," + (p_values[3].boolean ? "true" : "false") + ")"; + case SL::TYPE_INT: + return rtos(p_values[0].sint); + case SL::TYPE_IVEC2: + return String() + "ivec2(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + ")"; + case SL::TYPE_IVEC3: + return String() + "ivec3(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + ")"; + case SL::TYPE_IVEC4: + return String() + "ivec4(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + "," + rtos(p_values[3].sint) + ")"; + case SL::TYPE_UINT: + return rtos(p_values[0].real); + case SL::TYPE_UVEC2: + return String() + "uvec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; + case SL::TYPE_UVEC3: + return String() + "uvec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; + case SL::TYPE_UVEC4: + return String() + "uvec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; + case SL::TYPE_FLOAT: + return rtos(p_values[0].real); + case SL::TYPE_VEC2: + return String() + "vec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; + case SL::TYPE_VEC3: + return String() + "vec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; + case SL::TYPE_VEC4: + return String() + "vec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; + default: + ERR_FAIL_V(String()); + } +} + +static String dump_node_code(SL::Node *p_node, int p_level) { + String code; + + switch (p_node->type) { + case SL::Node::TYPE_SHADER: { + SL::ShaderNode *pnode = (SL::ShaderNode *)p_node; + + for (const KeyValue &E : pnode->uniforms) { + String ucode = "uniform "; + ucode += _prestr(E.value.precision); + ucode += _typestr(E.value.type); + ucode += " " + String(E.key); + if (E.value.array_size > 0) { + ucode += "["; + ucode += itos(E.value.array_size); + ucode += "]"; + } else { + if (E.value.default_value.size()) { + ucode += " = " + get_constant_text(E.value.type, E.value.default_value); + } + + static const char *hint_name[SL::ShaderNode::Uniform::HINT_MAX] = { + "", + "color", + "range", + "albedo", + "normal", + "black", + "white" + }; + + if (E.value.hint) { + ucode += " : " + String(hint_name[E.value.hint]); + } + } + + code += ucode + "\n"; + } + + for (const KeyValue &E : pnode->varyings) { + String vcode = "varying "; + vcode += _prestr(E.value.precision); + vcode += _typestr(E.value.type); + vcode += " " + String(E.key); + + code += vcode + "\n"; + } + for (int i = 0; i < pnode->functions.size(); i++) { + SL::FunctionNode *fnode = pnode->functions[i].function; + + String header; + header = _typestr(fnode->return_type) + " " + fnode->name + "("; + for (int j = 0; j < fnode->arguments.size(); j++) { + if (j > 0) { + header += ", "; + } + header += _prestr(fnode->arguments[j].precision) + _typestr(fnode->arguments[j].type) + " " + fnode->arguments[j].name; + } + + header += ")\n"; + code += header; + code += dump_node_code(fnode->body, p_level + 1); + } + + //code+=dump_node_code(pnode->body,p_level); + } break; + case SL::Node::TYPE_STRUCT: { + } break; + case SL::Node::TYPE_FUNCTION: { + } break; + case SL::Node::TYPE_BLOCK: { + SL::BlockNode *bnode = (SL::BlockNode *)p_node; + + //variables + code += _mktab(p_level - 1) + "{\n"; + for (const KeyValue &E : bnode->variables) { + code += _mktab(p_level) + _prestr(E.value.precision) + _typestr(E.value.type) + " " + E.key + ";\n"; + } + + for (int i = 0; i < bnode->statements.size(); i++) { + String scode = dump_node_code(bnode->statements[i], p_level); + + if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW) { + code += scode; //use directly + } else { + code += _mktab(p_level) + scode + ";\n"; + } + } + code += _mktab(p_level - 1) + "}\n"; + + } break; + case SL::Node::TYPE_VARIABLE: { + SL::VariableNode *vnode = (SL::VariableNode *)p_node; + code = vnode->name; + + } break; + case SL::Node::TYPE_VARIABLE_DECLARATION: { + // FIXME: Implement + } break; + case SL::Node::TYPE_ARRAY: { + SL::ArrayNode *vnode = (SL::ArrayNode *)p_node; + code = vnode->name; + } break; + case SL::Node::TYPE_ARRAY_DECLARATION: { + // FIXME: Implement + } break; + case SL::Node::TYPE_ARRAY_CONSTRUCT: { + // FIXME: Implement + } break; + case SL::Node::TYPE_CONSTANT: { + SL::ConstantNode *cnode = (SL::ConstantNode *)p_node; + return get_constant_text(cnode->datatype, cnode->values); + + } break; + case SL::Node::TYPE_OPERATOR: { + SL::OperatorNode *onode = (SL::OperatorNode *)p_node; + + switch (onode->op) { + case SL::OP_ASSIGN: + case SL::OP_ASSIGN_ADD: + case SL::OP_ASSIGN_SUB: + case SL::OP_ASSIGN_MUL: + case SL::OP_ASSIGN_DIV: + case SL::OP_ASSIGN_SHIFT_LEFT: + case SL::OP_ASSIGN_SHIFT_RIGHT: + case SL::OP_ASSIGN_MOD: + case SL::OP_ASSIGN_BIT_AND: + case SL::OP_ASSIGN_BIT_OR: + case SL::OP_ASSIGN_BIT_XOR: + code = dump_node_code(onode->arguments[0], p_level) + _opstr(onode->op) + dump_node_code(onode->arguments[1], p_level); + break; + case SL::OP_BIT_INVERT: + case SL::OP_NEGATE: + case SL::OP_NOT: + case SL::OP_DECREMENT: + case SL::OP_INCREMENT: + code = _opstr(onode->op) + dump_node_code(onode->arguments[0], p_level); + break; + case SL::OP_POST_DECREMENT: + case SL::OP_POST_INCREMENT: + code = dump_node_code(onode->arguments[0], p_level) + _opstr(onode->op); + break; + case SL::OP_CALL: + case SL::OP_CONSTRUCT: + code = dump_node_code(onode->arguments[0], p_level) + "("; + for (int i = 1; i < onode->arguments.size(); i++) { + if (i > 1) { + code += ", "; + } + code += dump_node_code(onode->arguments[i], p_level); + } + code += ")"; + break; + default: { + code = "(" + dump_node_code(onode->arguments[0], p_level) + _opstr(onode->op) + dump_node_code(onode->arguments[1], p_level) + ")"; + break; + } + } + + } break; + case SL::Node::TYPE_CONTROL_FLOW: { + SL::ControlFlowNode *cfnode = (SL::ControlFlowNode *)p_node; + if (cfnode->flow_op == SL::FLOW_OP_IF) { + code += _mktab(p_level) + "if (" + dump_node_code(cfnode->expressions[0], p_level) + ")\n"; + code += dump_node_code(cfnode->blocks[0], p_level + 1); + if (cfnode->blocks.size() == 2) { + code += _mktab(p_level) + "else\n"; + code += dump_node_code(cfnode->blocks[1], p_level + 1); + } + + } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) { + if (cfnode->blocks.size()) { + code = "return " + dump_node_code(cfnode->blocks[0], p_level); + } else { + code = "return"; + } + } + + } break; + case SL::Node::TYPE_MEMBER: { + SL::MemberNode *mnode = (SL::MemberNode *)p_node; + code = dump_node_code(mnode->owner, p_level) + "." + mnode->name; + + } break; + } + + return code; +} + +static Error recreate_code(void *p_str, SL::ShaderNode *p_program) { + String *str = (String *)p_str; + + *str = dump_node_code(p_program, 0); + + return OK; +} + +MainLoop *test() { + List cmdlargs = OS::get_singleton()->get_cmdline_args(); + + if (cmdlargs.is_empty()) { + //try editor! + print_line("usage: godot -test shader_lang "); + return nullptr; + } + + String test = cmdlargs.back()->get(); + + FileAccess *fa = FileAccess::open(test, FileAccess::READ); + + if (!fa) { + ERR_FAIL_V(nullptr); + } + + String code; + + while (true) { + char32_t c = fa->get_8(); + if (fa->eof_reached()) { + break; + } + code += c; + } + + SL sl; + print_line("tokens:\n\n" + sl.token_debug(code)); + + Map dt; + dt["fragment"].built_ins["ALBEDO"] = SL::TYPE_VEC3; + dt["fragment"].can_discard = true; + + Vector rm; + rm.push_back("popo"); + Set types; + types.insert("spatial"); + + Error err = sl.compile(code, dt, rm, ShaderLanguage::VaryingFunctionNames(), types, nullptr); + + if (err) { + print_line("Error at line: " + rtos(sl.get_error_line()) + ": " + sl.get_error_text()); + return nullptr; + } else { + String code2; + recreate_code(&code2, sl.get_shader()); + print_line("code:\n\n" + code2); + } + + return nullptr; +} +} // namespace TestShaderLang diff --git a/tests/servers/test_shader_lang.h b/tests/servers/test_shader_lang.h new file mode 100644 index 0000000000..de7ec002b6 --- /dev/null +++ b/tests/servers/test_shader_lang.h @@ -0,0 +1,41 @@ +/*************************************************************************/ +/* test_shader_lang.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_SHADER_LANG_H +#define TEST_SHADER_LANG_H + +class MainLoop; + +namespace TestShaderLang { + +MainLoop *test(); +} + +#endif // TEST_SHADER_LANG_H diff --git a/tests/servers/test_text_server.h b/tests/servers/test_text_server.h new file mode 100644 index 0000000000..4edffe3711 --- /dev/null +++ b/tests/servers/test_text_server.h @@ -0,0 +1,296 @@ +/*************************************************************************/ +/* test_text_server.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef TOOLS_ENABLED + +#ifndef TEST_TEXT_SERVER_H +#define TEST_TEXT_SERVER_H + +#include "editor/builtin_fonts.gen.h" +#include "servers/text_server.h" +#include "tests/test_macros.h" + +namespace TestTextServer { + +TEST_SUITE("[[TextServer]") { + TEST_CASE("[TextServer] Init, font loading and shaping") { + SUBCASE("[TextServer] Loading fonts") { + for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { + Ref ts = TextServerManager::get_singleton()->get_interface(i); + TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + + RID font = ts->create_font(); + ts->font_set_data_ptr(font, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + TEST_FAIL_COND(font == RID(), "Loading font failed."); + ts->free(font); + } + } + + SUBCASE("[TextServer] Text layout: Font fallback") { + for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { + Ref ts = TextServerManager::get_singleton()->get_interface(i); + TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + + RID font1 = ts->create_font(); + ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + RID font2 = ts->create_font(); + ts->font_set_data_ptr(font2, _font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size); + + Vector font; + font.push_back(font1); + font.push_back(font2); + + String test = U"คนอ้วน khon uan ראה"; + // 6^ 17^ + + RID ctx = ts->create_shaped_text(); + TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + bool ok = ts->shaped_text_add_string(ctx, test, font, 16); + TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + + const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx); + int gl_size = ts->shaped_text_get_glyph_count(ctx); + TEST_FAIL_COND(gl_size == 0, "Shaping failed"); + for (int j = 0; j < gl_size; j++) { + if (glyphs[j].start < 6) { + TEST_FAIL_COND(glyphs[j].font_rid != font[1], "Incorrect font selected."); + } + if ((glyphs[j].start > 6) && (glyphs[j].start < 16)) { + TEST_FAIL_COND(glyphs[j].font_rid != font[0], "Incorrect font selected."); + } + if (glyphs[j].start > 16) { + TEST_FAIL_COND(glyphs[j].font_rid != RID(), "Incorrect font selected."); + TEST_FAIL_COND(glyphs[j].index != test[glyphs[j].start], "Incorrect glyph index."); + } + TEST_FAIL_COND((glyphs[j].start < 0 || glyphs[j].end > test.length()), "Incorrect glyph range."); + TEST_FAIL_COND(glyphs[j].font_size != 16, "Incorrect glyph font size."); + } + + ts->free(ctx); + + for (int j = 0; j < font.size(); j++) { + ts->free(font[j]); + } + font.clear(); + } + } + + SUBCASE("[TextServer] Text layout: BiDi") { + for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { + Ref ts = TextServerManager::get_singleton()->get_interface(i); + TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + + if (!ts->has_feature(TextServer::FEATURE_BIDI_LAYOUT)) { + continue; + } + + RID font1 = ts->create_font(); + ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + RID font2 = ts->create_font(); + ts->font_set_data_ptr(font2, _font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size); + + Vector font; + font.push_back(font1); + font.push_back(font2); + + String test = U"Arabic (اَلْعَرَبِيَّةُ, al-ʿarabiyyah)"; + // 7^ 26^ + + RID ctx = ts->create_shaped_text(); + TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + bool ok = ts->shaped_text_add_string(ctx, test, font, 16); + TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + + const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx); + int gl_size = ts->shaped_text_get_glyph_count(ctx); + TEST_FAIL_COND(gl_size == 0, "Shaping failed"); + for (int j = 0; j < gl_size; j++) { + if (glyphs[j].count > 0) { + if (glyphs[j].start < 7) { + TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction."); + } + if ((glyphs[j].start > 8) && (glyphs[j].start < 23)) { + TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) != TextServer::GRAPHEME_IS_RTL), "Incorrect direction."); + } + if (glyphs[j].start > 26) { + TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction."); + } + } + } + + ts->free(ctx); + + for (int j = 0; j < font.size(); j++) { + ts->free(font[j]); + } + font.clear(); + } + } + + SUBCASE("[TextServer] Text layout: Line breaking") { + for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { + Ref ts = TextServerManager::get_singleton()->get_interface(i); + TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + + String test_1 = U"test test test"; + // 5^ 10^ + + RID font1 = ts->create_font(); + ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + RID font2 = ts->create_font(); + ts->font_set_data_ptr(font2, _font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size); + + Vector font; + font.push_back(font1); + font.push_back(font2); + + RID ctx = ts->create_shaped_text(); + TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + bool ok = ts->shaped_text_add_string(ctx, test_1, font, 16); + TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + + PackedInt32Array brks = ts->shaped_text_get_line_breaks(ctx, 1); + TEST_FAIL_COND(brks.size() != 6, "Invalid line breaks number."); + if (brks.size() == 6) { + TEST_FAIL_COND(brks[0] != 0, "Invalid line break position."); + TEST_FAIL_COND(brks[1] != 5, "Invalid line break position."); + + TEST_FAIL_COND(brks[2] != 5, "Invalid line break position."); + TEST_FAIL_COND(brks[3] != 10, "Invalid line break position."); + + TEST_FAIL_COND(brks[4] != 10, "Invalid line break position."); + TEST_FAIL_COND(brks[5] != 14, "Invalid line break position."); + } + + ts->free(ctx); + + for (int j = 0; j < font.size(); j++) { + ts->free(font[j]); + } + font.clear(); + } + } + + SUBCASE("[TextServer] Text layout: Justification") { + for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { + Ref ts = TextServerManager::get_singleton()->get_interface(i); + TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + + RID font1 = ts->create_font(); + ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + RID font2 = ts->create_font(); + ts->font_set_data_ptr(font2, _font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size); + + Vector font; + font.push_back(font1); + font.push_back(font2); + + String test_1 = U"الحمد"; + String test_2 = U"الحمد test"; + String test_3 = U"test test"; + // 7^ 26^ + + RID ctx; + bool ok; + float width_old, width; + if (ts->has_feature(TextServer::FEATURE_KASHIDA_JUSTIFICATION)) { + ctx = ts->create_shaped_text(); + TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + ok = ts->shaped_text_add_string(ctx, test_1, font, 16); + TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + + width_old = ts->shaped_text_get_width(ctx); + width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND); + TEST_FAIL_COND((width != width_old), "Invalid fill width."); + width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); + TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width."); + + ts->free(ctx); + + ctx = ts->create_shaped_text(); + TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + ok = ts->shaped_text_add_string(ctx, test_2, font, 16); + TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + + width_old = ts->shaped_text_get_width(ctx); + width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND); + TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width."); + width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); + TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width."); + + ts->free(ctx); + } + + ctx = ts->create_shaped_text(); + TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + ok = ts->shaped_text_add_string(ctx, test_3, font, 16); + TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + + width_old = ts->shaped_text_get_width(ctx); + width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND); + TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width."); + + ts->free(ctx); + + for (int j = 0; j < font.size(); j++) { + ts->free(font[j]); + } + font.clear(); + } + } + + SUBCASE("[TextServer] Strip Diacritics") { + for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { + Ref ts = TextServerManager::get_singleton()->get_interface(i); + TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + + if (ts->has_feature(TextServer::FEATURE_SHAPING)) { + CHECK(ts->strip_diacritics(U"ٱلسَّلَامُ عَلَيْكُمْ") == U"ٱلسلام عليكم"); + } + + CHECK(ts->strip_diacritics(U"pêches épinards tomates fraises") == U"peches epinards tomates fraises"); + CHECK(ts->strip_diacritics(U"ΆΈΉΊΌΎΏΪΫϓϔ") == U"ΑΕΗΙΟΥΩΙΥΥΥ"); + CHECK(ts->strip_diacritics(U"άέήίΐϊΰϋόύώ") == U"αεηιιιυυουω"); + CHECK(ts->strip_diacritics(U"ЀЁЃ ЇЌЍӢӤЙ ЎӮӰӲ ӐӒӖӚӜӞ ӦӪ Ӭ Ӵ Ӹ") == U"ЕЕГ ІКИИИИ УУУУ ААЕӘЖЗ ОӨ Э Ч Ы"); + CHECK(ts->strip_diacritics(U"ѐёѓ їќѝӣӥй ўӯӱӳ ӑӓӗӛӝӟ ӧӫ ӭ ӵ ӹ") == U"еег ікииии уууу ааеәжз оө э ч ы"); + CHECK(ts->strip_diacritics(U"ÀÁÂÃÄÅĀĂĄÇĆĈĊČĎÈÉÊËĒĔĖĘĚĜĞĠĢĤÌÍÎÏĨĪĬĮİĴĶĹĻĽÑŃŅŇŊÒÓÔÕÖØŌŎŐƠŔŖŘŚŜŞŠŢŤÙÚÛÜŨŪŬŮŰŲƯŴÝŶŹŻŽ") == U"AAAAAAAAACCCCCDEEEEEEEEEGGGGHIIIIIIIIIJKLLLNNNNŊOOOOOØOOOORRRSSSSTTUUUUUUUUUUUWYYZZZ"); + CHECK(ts->strip_diacritics(U"àáâãäåāăąçćĉċčďèéêëēĕėęěĝğġģĥìíîïĩīĭįĵķĺļľñńņňŋòóôõöøōŏőơŕŗřśŝşšţťùúûüũūŭůűųưŵýÿŷźżž") == U"aaaaaaaaacccccdeeeeeeeeegggghiiiiiiiijklllnnnnŋoooooøoooorrrssssttuuuuuuuuuuuwyyyzzz"); + CHECK(ts->strip_diacritics(U"ǍǏȈǑǪǬȌȎȪȬȮȰǓǕǗǙǛȔȖǞǠǺȀȂȦǢǼǦǴǨǸȆȐȒȘȚȞȨ Ḁ ḂḄḆ Ḉ ḊḌḎḐḒ ḔḖḘḚḜ Ḟ Ḡ ḢḤḦḨḪ ḬḮ ḰḲḴ ḶḸḺḼ ḾṀṂ ṄṆṈṊ ṌṎṐṒ ṔṖ ṘṚṜṞ ṠṢṤṦṨ ṪṬṮṰ ṲṴṶṸṺ") == U"AIIOOOOOOOOOUUUUUUUAAAAAAÆÆGGKNERRSTHE A BBB C DDDDD EEEEE F G HHHHH II KKK LLLL MMM NNNN OOOO PP RRRR SSSSS TTTT UUUUU"); + CHECK(ts->strip_diacritics(U"ǎǐȉȋǒǫǭȍȏȫȭȯȱǔǖǘǚǜȕȗǟǡǻȁȃȧǣǽǧǵǩǹȇȑȓșțȟȩ ḁ ḃḅḇ ḉ ḋḍḏḑḓ ḟ ḡ ḭḯ ḱḳḵ ḷḹḻḽ ḿṁṃ ṅṇṉṋ ṍṏṑṓ ṗṕ ṙṛṝṟ ṡṣṥṧṩ ṫṭṯṱ ṳṵṷṹṻ") == U"aiiiooooooooouuuuuuuaaaaaaææggknerrsthe a bbb c ddddd f g ii kkk llll mmm nnnn oooo pp rrrr sssss tttt uuuuu"); + CHECK(ts->strip_diacritics(U"ṼṾ ẀẂẄẆẈ ẊẌ Ẏ ẐẒẔ") == U"VV WWWWW XX Y ZZZ"); + CHECK(ts->strip_diacritics(U"ṽṿ ẁẃẅẇẉ ẋẍ ẏ ẑẓẕ ẖ ẗẘẙẛ") == U"vv wwwww xx y zzz h twys"); + } + } + } +} +}; // namespace TestTextServer + +#endif // TEST_TEXT_SERVER_H +#endif // TOOLS_ENABLED -- cgit v1.2.3