diff options
Diffstat (limited to 'main/tests/test_misc.cpp')
| -rw-r--r-- | main/tests/test_misc.cpp | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/main/tests/test_misc.cpp b/main/tests/test_misc.cpp new file mode 100644 index 000000000..68564c62b --- /dev/null +++ b/main/tests/test_misc.cpp @@ -0,0 +1,499 @@ +/*************************************************************************/ +/* test_misc.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_misc.h" +#include "servers/visual_server.h" +#include "os/main_loop.h" +#include "math_funcs.h" +#include "print_string.h" + + +namespace TestMisc { + +struct ConvexTestResult +{ + + Vector3 edgeA[2]; + Vector3 edgeB[2]; + bool valid; + Vector3 contactA; + Vector3 contactB; + Vector3 contactNormal; + float depth; + + /* + Vector3 contactA; + Vector3 contactB; + Vector3 contactNormal; + Vector3 contactX; + Vector3 contactY; + Vector3 edgeA[2]; + Vector3 edgeB[2]; + float depth; + bool valid; + bool isEdgeEdge; + bool needTransform; + neBool ComputerEdgeContactPoint(ConvexTestResult & res); + neBool ComputerEdgeContactPoint2(float & au, float & bu); + void Reverse() + { + neSwap(contactA, contactB); + contactNormal *= -1.0f; + }*/ + bool ComputerEdgeContactPoint2(float & au, float & bu); +}; + + + +bool ConvexTestResult::ComputerEdgeContactPoint2(float & au, float & bu) +{ + float d1343, d4321, d1321, d4343, d2121; + float numer, denom; + + Vector3 p13; + Vector3 p43; + Vector3 p21; + Vector3 diff; + + p13 = (edgeA[0]) - (edgeB[0]); + p43 = (edgeB[1]) - (edgeB[0]); + + if ( p43.length_squared() < CMP_EPSILON2 ) + { + valid = false; + goto ComputerEdgeContactPoint2_Exit; + } + + p21 = (edgeA[1]) - (edgeA[0]); + + if ( p21.length_squared()<CMP_EPSILON2 ) + { + valid = false; + goto ComputerEdgeContactPoint2_Exit; + } + + d1343 = p13.dot(p43); + d4321 = p43.dot(p21); + d1321 = p13.dot(p21); + d4343 = p43.dot(p43); + d2121 = p21.dot(p21); + + denom = d2121 * d4343 - d4321 * d4321; + + if (ABS(denom) < CMP_EPSILON) + { + valid = false; + + goto ComputerEdgeContactPoint2_Exit; + } + + numer = d1343 * d4321 - d1321 * d4343; + au = numer / denom; + bu = (d1343 + d4321 * (au)) / d4343; + + if (au < 0.0f || au >= 1.0f) + { + valid = false; + } + else if (bu < 0.0f || bu >= 1.0f) + { + valid = false; + } + else + { + valid = true; + } + { + Vector3 tmpv; + + tmpv = p21 * au; + contactA = (edgeA[0]) + tmpv; + + tmpv = p43 * bu; + contactB = (edgeB[0]) + tmpv; + } + + diff = contactA - contactB; + + depth = Math::sqrt(diff.dot(diff)); + + return true; + +ComputerEdgeContactPoint2_Exit: + + return false; +} + +struct neCollisionResult { + + float depth; + bool penetrate; + Matrix3 collisionFrame; + Vector3 contactA; + Vector3 contactB; +}; + + +struct TConvex { + + float radius; + float half_height; + float CylinderRadius() const { return radius; } + float CylinderHalfHeight() const { return half_height; } +}; + +float GetDistanceFromLine2(Vector3 v, Vector3 & project, const Vector3 & pointA, const Vector3 & pointB) +{ + Vector3 ba = pointB - pointA; + + float len = ba.length(); + + if (len<CMP_EPSILON) + ba=Vector3(); + else + ba *= 1.0f / len; + + Vector3 pa = v - pointA; + + float k = pa.dot(ba); + + project = pointA + ba * k; + + Vector3 diff = v - project; + + return diff.length(); +} + +void TestCylinderVertEdge(neCollisionResult & result, Vector3 & edgeA1, Vector3 & edgeA2, Vector3 & vertB, + TConvex & cA, TConvex & cB, Transform & transA, Transform & transB, bool flip) +{ + Vector3 project; + + float dist = GetDistanceFromLine2(vertB,project, edgeA1, edgeA2); + + float depth = cA.CylinderRadius() + cB.CylinderRadius() - dist; + + if (depth <= 0.0f) + return; + + if (depth <= result.depth) + return; + + result.penetrate = true; + + result.depth = depth; + + if (!flip) + { + result.collisionFrame.set_axis(2,(project - vertB).normalized()); + + result.contactA = project - result.collisionFrame.get_axis(2) * cA.CylinderRadius(); + + result.contactB = vertB + result.collisionFrame.get_axis(2) * cB.CylinderRadius(); + } + else + { + + result.collisionFrame.set_axis(2,(vertB - project).normalized()); + + result.contactA = vertB - result.collisionFrame.get_axis(2) * cB.CylinderRadius(); + + result.contactB = project + result.collisionFrame.get_axis(2) * cA.CylinderRadius(); + } +} + +void TestCylinderVertVert(neCollisionResult & result, Vector3 & vertA, Vector3 & vertB, + TConvex & cA, TConvex & cB, Transform & transA, Transform & transB) +{ + Vector3 diff = vertA - vertB; + + float dist = diff.length(); + + float depth = cA.CylinderRadius() + cB.CylinderRadius() - dist; + + if (depth <= 0.0f) + return; + + if (depth <= result.depth) + return; + + result.penetrate = true; + + result.depth = depth; + + result.collisionFrame.set_axis(2, diff * (1.0f / dist)); + + result.contactA = vertA - result.collisionFrame.get_axis(2) * cA.CylinderRadius(); + + result.contactB = vertB + result.collisionFrame.get_axis(2) * cB.CylinderRadius(); +} + +void Cylinder2CylinderTest(neCollisionResult & result, TConvex & cA, Transform & transA, TConvex & cB, Transform & transB) +{ + result.penetrate = false; + + Vector3 dir = transA.basis.get_axis(1).cross(transB.basis.get_axis(1)); + + float len = dir.length(); + +// bool isParallel = len<CMP_EPSILON; + +// int doVertCheck = 0; + + ConvexTestResult cr; + + cr.edgeA[0] = transA.origin + transA.basis.get_axis(1) * cA.CylinderHalfHeight(); + cr.edgeA[1] = transA.origin - transA.basis.get_axis(1) * cA.CylinderHalfHeight(); + cr.edgeB[0] = transB.origin + transB.basis.get_axis(1) * cB.CylinderHalfHeight(); + cr.edgeB[1] = transB.origin - transB.basis.get_axis(1) * cB.CylinderHalfHeight(); + +// float dot = transA.basis.get_axis(1).dot(transB.basis.get_axis(1)); + + if (len>CMP_EPSILON) + { + float au, bu; + + cr.ComputerEdgeContactPoint2(au, bu); + + if (cr.valid) + { + float depth = cA.CylinderRadius() + cB.CylinderRadius() - cr.depth; + + if (depth <= 0.0f) + return; + + result.depth = depth; + + result.penetrate = true; + + result.collisionFrame.set_axis(2, (cr.contactA - cr.contactB)*(1.0f / cr.depth)); + + result.contactA = cr.contactA - result.collisionFrame.get_axis(2) * cA.CylinderRadius(); + + result.contactB = cr.contactB + result.collisionFrame.get_axis(2) * cB.CylinderRadius(); + + return; + } + } + result.depth = -1.0e6f; + + int i; + + for (i = 0; i < 2; i++) + { + //project onto edge b + + Vector3 diff = cr.edgeA[i] - cr.edgeB[1]; + + float dot = diff.dot(transB.basis.get_axis(1)); + + if (dot < 0.0f) + { + TestCylinderVertVert(result, cr.edgeA[i], cr.edgeB[1], cA, cB, transA, transB); + } + else if (dot > (2.0f * cB.CylinderHalfHeight())) + { + TestCylinderVertVert(result, cr.edgeA[i], cr.edgeB[0], cA, cB, transA, transB); + } + else + { + TestCylinderVertEdge(result, cr.edgeB[0], cr.edgeB[1], cr.edgeA[i], cB, cA, transB, transA, true); + } + } + for (i = 0; i < 2; i++) + { + //project onto edge b + + Vector3 diff = cr.edgeB[i] - cr.edgeA[1]; + + float dot = diff.dot(transA.basis.get_axis(1)); + + if (dot < 0.0f) + { + TestCylinderVertVert(result, cr.edgeB[i], cr.edgeA[1], cA, cB, transA, transB); + } + else if (dot > (2.0f * cB.CylinderHalfHeight())) + { + TestCylinderVertVert(result, cr.edgeB[i], cr.edgeA[0], cA, cB, transA, transB); + } + else + { + TestCylinderVertEdge(result, cr.edgeA[0], cr.edgeA[1], cr.edgeB[i], cA, cB, transA, transB, false); + } + } +} + + +class TestMainLoop : public MainLoop { + + RID meshA; + RID meshB; + RID poly; + RID instance; + RID camera; + RID viewport; + RID boxA; + RID boxB; + RID scenario; + + Transform rot_a; + Transform rot_b; + + bool quit; +public: + virtual void input_event(const InputEvent& p_event) { + + if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&BUTTON_MASK_LEFT) { + + rot_b.origin.y+=-p_event.mouse_motion.relative_y/100.0; + rot_b.origin.x+=p_event.mouse_motion.relative_x/100.0; + } + if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&BUTTON_MASK_MIDDLE) { + + //rot_b.origin.x+=-p_event.mouse_motion.relative_y/100.0; + rot_b.origin.z+=p_event.mouse_motion.relative_x/100.0; + } + if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&BUTTON_MASK_RIGHT) { + + float rot_x=-p_event.mouse_motion.relative_y/100.0; + float rot_y=p_event.mouse_motion.relative_x/100.0; + rot_b.basis = rot_b.basis * Matrix3(Vector3(1,0,0),rot_x) * Matrix3(Vector3(0,1,0),rot_y); + } + + } + virtual void request_quit() { + + quit=true; + } + virtual void init() { + + VisualServer *vs=VisualServer::get_singleton(); + + camera = vs->camera_create(); + + viewport = vs->viewport_create(); + vs->viewport_attach_to_screen(viewport); + vs->viewport_attach_camera( viewport, camera ); + vs->camera_set_transform(camera, Transform( Matrix3(), Vector3(0,0,3 ) ) ); + + /* CONVEX SHAPE */ + + DVector<Plane> cylinder_planes = Geometry::build_cylinder_planes(0.5,2,9,Vector3::AXIS_Y); + RID cylinder_material = vs->fixed_material_create(); + vs->fixed_material_set_param( cylinder_material, VisualServer::FIXED_MATERIAL_PARAM_DIFFUSE, Color(0.8,0.2,0.9)); + vs->material_set_flag( cylinder_material, VisualServer::MATERIAL_FLAG_ONTOP,true); + //vs->material_set_flag( cylinder_material, VisualServer::MATERIAL_FLAG_WIREFRAME,true); + vs->material_set_flag( cylinder_material, VisualServer::MATERIAL_FLAG_DOUBLE_SIDED,true); + vs->material_set_flag( cylinder_material, VisualServer::MATERIAL_FLAG_UNSHADED,true); + + RID cylinder_mesh = vs->mesh_create(); + Geometry::MeshData cylinder_data = Geometry::build_convex_mesh(cylinder_planes); + vs->mesh_add_surface_from_mesh_data(cylinder_mesh,cylinder_data); + vs->mesh_surface_set_material( cylinder_mesh, 0, cylinder_material ); + + meshA=vs->instance_create2(cylinder_mesh,scenario); + meshB=vs->instance_create2(cylinder_mesh,scenario); + boxA=vs->instance_create2(vs->get_test_cube(),scenario); + boxB=vs->instance_create2(vs->get_test_cube(),scenario); + + /* + RID lightaux = vs->light_create( VisualServer::LIGHT_OMNI ); + vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_RADIUS, 80 ); + vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ATTENUATION, 1 ); + vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ENERGY, 1.5 ); + light = vs->instance_create2( lightaux ); + */ + RID lightaux = vs->light_create( VisualServer::LIGHT_DIRECTIONAL ); + //vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) ); + //vs->light_set_shadow( lightaux, true ); + RID light = vs->instance_create2( lightaux,scenario ); + + //rot_a=Transform(Matrix3(Vector3(1,0,0),Math_PI/2.0),Vector3()); + rot_b=Transform(Matrix3(),Vector3(2,0,0)); + + //rot_x=0; + //rot_y=0; + quit=false; + } + virtual bool idle(float p_time) { + + VisualServer *vs=VisualServer::get_singleton(); + + vs->instance_set_transform(meshA,rot_a); + vs->instance_set_transform(meshB,rot_b); + + + neCollisionResult res; + TConvex a; + a.radius=0.5; + a.half_height=1; + Cylinder2CylinderTest(res,a,rot_a,a,rot_b); + if (res.penetrate) { + + Matrix3 scale; + scale.scale(Vector3(0.1,0.1,0.1)); + vs->instance_set_transform(boxA,Transform(scale,res.contactA)); + vs->instance_set_transform(boxB,Transform(scale,res.contactB)); + print_line("depth: "+rtos(res.depth)); + } else { + + Matrix3 scale; + scale.scale(Vector3()); + vs->instance_set_transform(boxA,Transform(scale,res.contactA)); + vs->instance_set_transform(boxB,Transform(scale,res.contactB)); + + } + print_line("collided: "+itos(res.penetrate)); + + return false; + } + + + virtual bool iteration(float p_time) { + + + + return quit; + } + virtual void finish() { + + } + +}; + + +MainLoop* test() { + + return memnew( TestMainLoop ); + +} + +} + + + |
