diff options
author | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
commit | 0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch) | |
tree | 276c4d099e178eb67fbd14f61d77b05e3808e9e3 /scene/3d | |
parent | 0e49da1687bc8192ed210947da52c9e5c5f301bb (diff) |
GODOT IS OPEN SOURCE
Diffstat (limited to 'scene/3d')
69 files changed, 15239 insertions, 0 deletions
diff --git a/scene/3d/SCsub b/scene/3d/SCsub new file mode 100644 index 0000000000..6789851aab --- /dev/null +++ b/scene/3d/SCsub @@ -0,0 +1,14 @@ +Import('env') + + +print("V: "+env["disable_3d"]) +if (env["disable_3d"]=="yes"): + + env.scene_sources.append("3d/spatial.cpp") + env.scene_sources.append("3d/skeleton.cpp") +else: + env.add_source_files(env.scene_sources,"*.cpp") + +Export('env') + + diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp new file mode 100644 index 0000000000..964a086cf6 --- /dev/null +++ b/scene/3d/area.cpp @@ -0,0 +1,317 @@ +/*************************************************************************/ +/* area.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "area.h" +#include "scene/scene_string_names.h" +#include "servers/physics_server.h" +void Area::set_space_override_mode(SpaceOverride p_mode) { + + space_override=p_mode; + PhysicsServer::get_singleton()->area_set_space_override_mode(get_rid(),PhysicsServer::AreaSpaceOverrideMode(p_mode)); + + +} +Area::SpaceOverride Area::get_space_override_mode() const{ + + return space_override; +} + +void Area::set_gravity_is_point(bool p_enabled){ + + gravity_is_point=p_enabled; + PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT,p_enabled); + +} +bool Area::is_gravity_a_point() const{ + + return gravity_is_point; +} + +void Area::set_gravity_vector(const Vector3& p_vec){ + + gravity_vec=p_vec; + PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_GRAVITY_VECTOR,p_vec); + +} +Vector3 Area::get_gravity_vector() const{ + + return gravity_vec; +} + +void Area::set_gravity(real_t p_gravity){ + + gravity=p_gravity; + PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_GRAVITY,p_gravity); +} +real_t Area::get_gravity() const{ + + return gravity; +} + +void Area::set_density(real_t p_density){ + + density=p_density; + PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_DENSITY,p_density); +} +real_t Area::get_density() const{ + + return density; +} + +void Area::set_priority(real_t p_priority){ + + priority=p_priority; + PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_PRIORITY,p_priority); +} +real_t Area::get_priority() const{ + + return priority; +} + + +void Area::_body_enter_scene(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_FAIL_COND(!node); + + Map<ObjectID,BodyState>::Element *E=body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(E->get().in_scene); + + E->get().in_scene=true; + emit_signal(SceneStringNames::get_singleton()->body_enter,node); + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->body_enter_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape); + } + +} + +void Area::_body_exit_scene(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_FAIL_COND(!node); + Map<ObjectID,BodyState>::Element *E=body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(!E->get().in_scene); + E->get().in_scene=false; + emit_signal(SceneStringNames::get_singleton()->body_exit,node); + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape); + } + +} + +void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape) { + + bool body_in = p_status==PhysicsServer::AREA_BODY_ADDED; + ObjectID objid=p_instance; + + Object *obj = ObjectDB::get_instance(objid); + Node *node = obj ? obj->cast_to<Node>() : NULL; + + Map<ObjectID,BodyState>::Element *E=body_map.find(objid); + + ERR_FAIL_COND(!body_in && !E); + + if (body_in) { + if (!E) { + + E = body_map.insert(objid,BodyState()); + E->get().rc=0; + E->get().in_scene=node && node->is_inside_scene(); + if (node) { + node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid)); + if (E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_enter,node); + } + } + + } + E->get().rc++; + if (node) + E->get().shapes.insert(ShapePair(p_body_shape,p_area_shape)); + + + if (E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_enter_shape,objid,node,p_body_shape,p_area_shape); + } + + } else { + + E->get().rc--; + + if (node) + E->get().shapes.erase(ShapePair(p_body_shape,p_area_shape)); + + bool eraseit=false; + + if (E->get().rc==0) { + + if (node) { + node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); + node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); + if (E->get().in_scene) + emit_signal(SceneStringNames::get_singleton()->body_exit,obj); + + } + + eraseit=true; + + } + if (node && E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_area_shape); + } + + if (eraseit) + body_map.erase(E); + + } + +} + + +void Area::_clear_monitoring() { + + Map<ObjectID,BodyState> bmcopy = body_map; + body_map.clear(); + //disconnect all monitored stuff + + for (Map<ObjectID,BodyState>::Element *E=bmcopy.front();E;E=E->next()) { + + Object *obj = ObjectDB::get_instance(E->key()); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_CONTINUE(!node); + if (!E->get().in_scene) + continue; + + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,E->key(),node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape); + } + + emit_signal(SceneStringNames::get_singleton()->body_exit,obj); + + node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); + node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); + } + +} +void Area::_notification(int p_what) { + + if (p_what==NOTIFICATION_EXIT_SCENE) { + _clear_monitoring(); + } +} + +void Area::set_enable_monitoring(bool p_enable) { + + if (p_enable==monitoring) + return; + + monitoring=p_enable; + + if (monitoring) { + + PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout"); + } else { + PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName()); + _clear_monitoring(); + } +} + +bool Area::is_monitoring_enabled() const { + + return monitoring; +} + + +void Area::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_body_enter_scene","id"),&Area::_body_enter_scene); + ObjectTypeDB::bind_method(_MD("_body_exit_scene","id"),&Area::_body_exit_scene); + + ObjectTypeDB::bind_method(_MD("set_space_override_mode","enable"),&Area::set_space_override_mode); + ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area::get_space_override_mode); + + ObjectTypeDB::bind_method(_MD("set_gravity_is_point","enable"),&Area::set_gravity_is_point); + ObjectTypeDB::bind_method(_MD("is_gravity_a_point"),&Area::is_gravity_a_point); + + ObjectTypeDB::bind_method(_MD("set_gravity_vector","vector"),&Area::set_gravity_vector); + ObjectTypeDB::bind_method(_MD("get_gravity_vector"),&Area::get_gravity_vector); + + ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&Area::set_gravity); + ObjectTypeDB::bind_method(_MD("get_gravity"),&Area::get_gravity); + + ObjectTypeDB::bind_method(_MD("set_density","density"),&Area::set_density); + ObjectTypeDB::bind_method(_MD("get_density"),&Area::get_density); + + ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area::set_priority); + ObjectTypeDB::bind_method(_MD("get_priority"),&Area::get_priority); + + ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area::set_enable_monitoring); + ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area::is_monitoring_enabled); + + ObjectTypeDB::bind_method(_MD("_body_inout"),&Area::_body_inout); + + + ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape"))); + ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape"))); + ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body"))); + ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body"))); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"space_override",PROPERTY_HINT_ENUM,"Disabled,Combine,Replace"),_SCS("set_space_override_mode"),_SCS("get_space_override_mode")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"gravity_vec"),_SCS("set_gravity_vector"),_SCS("get_gravity_vector")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_gravity"),_SCS("get_gravity")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"density",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_density"),_SCS("get_density")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled")); + +} + +Area::Area() : CollisionObject(PhysicsServer::get_singleton()->area_create(),true) { + + space_override=SPACE_OVERRIDE_DISABLED; + set_gravity(9.8);; + set_gravity_vector(Vector3(0,-1,0)); + gravity_is_point=false; + density=0.1; + priority=0; + monitoring=false; + +} + +Area::~Area() { + + +} diff --git a/scene/3d/area.h b/scene/3d/area.h new file mode 100644 index 0000000000..79e98f9dab --- /dev/null +++ b/scene/3d/area.h @@ -0,0 +1,121 @@ +/*************************************************************************/ +/* area.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef AREA_H +#define AREA_H + +#include "scene/3d/collision_object.h" +#include "vset.h" + +class Area : public CollisionObject { + + OBJ_TYPE( Area, CollisionObject ); +public: + + enum SpaceOverride { + SPACE_OVERRIDE_DISABLED, + SPACE_OVERRIDE_COMBINE, + SPACE_OVERRIDE_REPLACE + }; +private: + + + SpaceOverride space_override; + Vector3 gravity_vec; + real_t gravity; + bool gravity_is_point; + real_t density; + int priority; + bool monitoring; + + void _body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape); + + void _body_enter_scene(ObjectID p_id); + void _body_exit_scene(ObjectID p_id); + + struct ShapePair { + + int body_shape; + int area_shape; + bool operator<(const ShapePair& p_sp) const { + if (body_shape==p_sp.body_shape) + return area_shape < p_sp.area_shape; + else + return body_shape < p_sp.body_shape; + } + + ShapePair() {} + ShapePair(int p_bs, int p_as) { body_shape=p_bs; area_shape=p_as; } + }; + + struct BodyState { + + int rc; + bool in_scene; + VSet<ShapePair> shapes; + }; + + Map<ObjectID,BodyState> body_map; + void _clear_monitoring(); + + +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_space_override_mode(SpaceOverride p_mode); + SpaceOverride get_space_override_mode() const; + + void set_gravity_is_point(bool p_enabled); + bool is_gravity_a_point() const; + + void set_gravity_vector(const Vector3& p_vec); + Vector3 get_gravity_vector() const; + + void set_gravity(real_t p_gravity); + real_t get_gravity() const; + + void set_density(real_t p_density); + real_t get_density() const; + + void set_priority(real_t p_priority); + real_t get_priority() const; + + void set_enable_monitoring(bool p_enable); + bool is_monitoring_enabled() const; + + + Area(); + ~Area(); +}; + +VARIANT_ENUM_CAST(Area::SpaceOverride); + +#endif // AREA__H diff --git a/scene/3d/body_shape.cpp b/scene/3d/body_shape.cpp new file mode 100644 index 0000000000..b291ce7c72 --- /dev/null +++ b/scene/3d/body_shape.cpp @@ -0,0 +1,829 @@ +/*************************************************************************/ +/* body_shape.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "body_shape.h" +#include "servers/visual_server.h" +#include "scene/resources/sphere_shape.h" +#include "scene/resources/ray_shape.h" +#include "scene/resources/box_shape.h" +#include "scene/resources/capsule_shape.h" +//#include "scene/resources/cylinder_shape.h" +#include "scene/resources/convex_polygon_shape.h" +#include "scene/resources/concave_polygon_shape.h" +#include "scene/resources/height_map_shape.h" +#include "scene/resources/plane_shape.h" +#include "mesh_instance.h" +#include "physics_body.h" +#include "quick_hull.h" + +void CollisionShape::_update_body() { + + + + if (get_parent() && get_parent()->cast_to<CollisionObject>()) + get_parent()->cast_to<CollisionObject>()->_update_shapes_from_children(); + +} + +void CollisionShape::make_convex_from_brothers() { + + Node *p = get_parent(); + if (!p) + return; + + for(int i=0;i<p->get_child_count();i++) { + + Node *n = p->get_child(i); + if (n->cast_to<MeshInstance>()) { + + MeshInstance *mi=n->cast_to<MeshInstance>(); + Ref<Mesh> m = mi->get_mesh(); + if (m.is_valid()) { + + Ref<Shape> s = m->create_convex_shape(); + set_shape(s); + } + } + } + +} + + +void CollisionShape::_update_indicator() { + + while (VisualServer::get_singleton()->mesh_get_surface_count(indicator)) + VisualServer::get_singleton()->mesh_remove_surface(indicator,0); + + if (shape.is_null()) + return; + + DVector<Vector3> points; + DVector<Vector3> normals; + + VS::PrimitiveType pt = VS::PRIMITIVE_TRIANGLES; + + if (shape->cast_to<RayShape>()) { + + RayShape *rs = shape->cast_to<RayShape>(); + points.push_back(Vector3()); + points.push_back(Vector3(0,0,rs->get_length())); + pt = VS::PRIMITIVE_LINES; + } else if (shape->cast_to<SphereShape>()) { + +// VisualServer *vs=VisualServer::get_singleton(); + SphereShape *shapeptr=shape->cast_to<SphereShape>(); + + + Color col(0.4,1.0,1.0,0.5); + + int lats=6; + int lons=12; + float size=shapeptr->get_radius(); + + + for(int i = 1; i <= lats; i++) { + double lat0 = Math_PI * (-0.5 + (double) (i - 1) / lats); + double z0 = Math::sin(lat0); + double zr0 = Math::cos(lat0); + + double lat1 = Math_PI * (-0.5 + (double) i / lats); + double z1 = Math::sin(lat1); + double zr1 = Math::cos(lat1); + + for(int j = lons; j >= 1; j--) { + + double lng0 = 2 * Math_PI * (double) (j - 1) / lons; + double x0 = Math::cos(lng0); + double y0 = Math::sin(lng0); + + double lng1 = 2 * Math_PI * (double) (j) / lons; + double x1 = Math::cos(lng1); + double y1 = Math::sin(lng1); + + Vector3 v4=Vector3(x0 * zr0, z0, y0 *zr0)*size; + Vector3 v3=Vector3(x0 * zr1, z1, y0 *zr1)*size; + Vector3 v2=Vector3(x1 * zr1, z1, y1 *zr1)*size; + Vector3 v1=Vector3(x1 * zr0, z0, y1 *zr0)*size; + + Vector<Vector3> line; + line.push_back(v1); + line.push_back(v2); + line.push_back(v3); + line.push_back(v4); + + + points.push_back(v1); + points.push_back(v2); + points.push_back(v3); + + points.push_back(v1); + points.push_back(v3); + points.push_back(v4); + + normals.push_back(v1.normalized()); + normals.push_back(v2.normalized()); + normals.push_back(v3.normalized()); + + normals.push_back(v1.normalized()); + normals.push_back(v3.normalized()); + normals.push_back(v4.normalized()); + + } + } + } else if (shape->cast_to<BoxShape>()) { + + BoxShape *shapeptr=shape->cast_to<BoxShape>(); + + for (int i=0;i<6;i++) { + + + Vector3 face_points[4]; + + + for (int j=0;j<4;j++) { + + float v[3]; + v[0]=1.0; + v[1]=1-2*((j>>1)&1); + v[2]=v[1]*(1-2*(j&1)); + + for (int k=0;k<3;k++) { + + if (i<3) + face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1); + else + face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1); + } + } + Vector3 normal; + normal[i%3]=(i>=3?-1:1); + + for(int j=0;j<4;j++) + face_points[j]*=shapeptr->get_extents(); + + points.push_back(face_points[0]); + points.push_back(face_points[1]); + points.push_back(face_points[2]); + + points.push_back(face_points[0]); + points.push_back(face_points[2]); + points.push_back(face_points[3]); + + for(int n=0;n<6;n++) + normals.push_back(normal); + + } + + } else if (shape->cast_to<ConvexPolygonShape>()) { + + ConvexPolygonShape *shapeptr=shape->cast_to<ConvexPolygonShape>(); + + Geometry::MeshData md; + QuickHull::build(Variant(shapeptr->get_points()),md); + + for(int i=0;i<md.faces.size();i++) { + + for(int j=2;j<md.faces[i].indices.size();j++) { + points.push_back(md.vertices[md.faces[i].indices[0]]); + points.push_back(md.vertices[md.faces[i].indices[j-1]]); + points.push_back(md.vertices[md.faces[i].indices[j]]); + normals.push_back(md.faces[i].plane.normal); + normals.push_back(md.faces[i].plane.normal); + normals.push_back(md.faces[i].plane.normal); + } + } + } else if (shape->cast_to<ConcavePolygonShape>()) { + + ConcavePolygonShape *shapeptr=shape->cast_to<ConcavePolygonShape>(); + + points = shapeptr->get_faces(); + for(int i=0;i<points.size()/3;i++) { + + Vector3 n = Plane( points[i*3+0],points[i*3+1],points[i*3+2] ).normal; + normals.push_back(n); + normals.push_back(n); + normals.push_back(n); + } + + } else if (shape->cast_to<CapsuleShape>()) { + + CapsuleShape *shapeptr=shape->cast_to<CapsuleShape>(); + + DVector<Plane> planes = Geometry::build_capsule_planes(shapeptr->get_radius(), shapeptr->get_height()/2.0, 12, Vector3::AXIS_Z); + Geometry::MeshData md = Geometry::build_convex_mesh(planes); + + for(int i=0;i<md.faces.size();i++) { + + for(int j=2;j<md.faces[i].indices.size();j++) { + points.push_back(md.vertices[md.faces[i].indices[0]]); + points.push_back(md.vertices[md.faces[i].indices[j-1]]); + points.push_back(md.vertices[md.faces[i].indices[j]]); + normals.push_back(md.faces[i].plane.normal); + normals.push_back(md.faces[i].plane.normal); + normals.push_back(md.faces[i].plane.normal); + + } + } + + } else if (shape->cast_to<PlaneShape>()) { + + PlaneShape *shapeptr=shape->cast_to<PlaneShape>(); + + Plane p = shapeptr->get_plane(); + Vector3 n1 = p.get_any_perpendicular_normal(); + Vector3 n2 = p.normal.cross(n1).normalized(); + + Vector3 pface[4]={ + p.normal*p.d+n1*100.0+n2*100.0, + p.normal*p.d+n1*100.0+n2*-100.0, + p.normal*p.d+n1*-100.0+n2*-100.0, + p.normal*p.d+n1*-100.0+n2*100.0, + }; + + points.push_back(pface[0]); + points.push_back(pface[1]); + points.push_back(pface[2]); + + points.push_back(pface[0]); + points.push_back(pface[2]); + points.push_back(pface[3]); + + normals.push_back(p.normal); + normals.push_back(p.normal); + normals.push_back(p.normal); + normals.push_back(p.normal); + normals.push_back(p.normal); + normals.push_back(p.normal); + + } + + if (!points.size()) + return; + RID material = VisualServer::get_singleton()->fixed_material_create(); + VisualServer::get_singleton()->fixed_material_set_param(material,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0,0.6,0.7,0.3)); + VisualServer::get_singleton()->fixed_material_set_param(material,VS::FIXED_MATERIAL_PARAM_EMISSION,0.7); + if (normals.size()==0) + VisualServer::get_singleton()->material_set_flag(material,VS::MATERIAL_FLAG_UNSHADED,true); + VisualServer::get_singleton()->material_set_flag(material,VS::MATERIAL_FLAG_DOUBLE_SIDED,true); + Array d; + d.resize(VS::ARRAY_MAX); + d[VS::ARRAY_VERTEX]=points; + if (normals.size()) + d[VS::ARRAY_NORMAL]=normals; + VisualServer::get_singleton()->mesh_add_surface(indicator,pt,d); + VisualServer::get_singleton()->mesh_surface_set_material(indicator,0,material,true); + +} + + +void CollisionShape::_add_to_collision_object(Object* p_cshape) { + + CollisionObject *co=p_cshape->cast_to<CollisionObject>(); + ERR_FAIL_COND(!co); + + if (shape.is_valid()) { + + co->add_shape(shape,get_transform()); + if (trigger) + co->set_shape_as_trigger( co->get_shape_count() -1, true ); + } +} + +void CollisionShape::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_WORLD: { + indicator_instance = VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario()); + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + VisualServer::get_singleton()->instance_set_transform(indicator_instance,get_global_transform()); + if (updating_body) { + _update_body(); + } + } break; + case NOTIFICATION_EXIT_WORLD: { + if (indicator_instance.is_valid()) { + VisualServer::get_singleton()->free(indicator_instance); + indicator_instance=RID(); + } + } break; + case NOTIFICATION_UNPARENTED: { + if (updating_body) + _update_body(); + } break; + case NOTIFICATION_PARENTED: { + if (updating_body) + _update_body(); + } break; + } +} + + +void CollisionShape::resource_changed(RES res) { + + update_gizmo(); + + +} + +void CollisionShape::_bind_methods() { + + //not sure if this should do anything + ObjectTypeDB::bind_method(_MD("resource_changed"),&CollisionShape::resource_changed); + ObjectTypeDB::bind_method(_MD("set_shape","shape"),&CollisionShape::set_shape); + ObjectTypeDB::bind_method(_MD("get_shape"),&CollisionShape::get_shape); + ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionShape::_add_to_collision_object); + ObjectTypeDB::bind_method(_MD("set_trigger","enable"),&CollisionShape::set_trigger); + ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionShape::is_trigger); + ObjectTypeDB::bind_method(_MD("make_convex_from_brothers"),&CollisionShape::make_convex_from_brothers); + ObjectTypeDB::set_method_flags("CollisionShape","make_convex_from_brothers",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + + + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), _SCS("set_shape"), _SCS("get_shape")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); +} + + +void CollisionShape::set_shape(const Ref<Shape> &p_shape) { + + if (!shape.is_null()) + shape->unregister_owner(this); + shape=p_shape; + if (!shape.is_null()) + shape->register_owner(this); + update_gizmo(); + if (updating_body) + _update_body(); +} + +Ref<Shape> CollisionShape::get_shape() const { + + return shape; +} + + +void CollisionShape::set_updating_body(bool p_update) { + updating_body=p_update; +} + +bool CollisionShape::is_updating_body() const { + + return updating_body; +} + +void CollisionShape::set_trigger(bool p_trigger) { + + trigger=p_trigger; + if (updating_body) + _update_body(); +} + +bool CollisionShape::is_trigger() const{ + + return trigger; +} + +CollisionShape::CollisionShape() { + + indicator = VisualServer::get_singleton()->mesh_create(); + updating_body=true; + trigger=false; +} + +CollisionShape::~CollisionShape() { + if (!shape.is_null()) + shape->unregister_owner(this); + VisualServer::get_singleton()->free(indicator); +} + +#if 0 +#include "body_volume.h" + +#include "scene/3d/physics_body.h" +#include "geometry.h" + +#define ADD_TRIANGLE( m_a, m_b, m_c, m_color)\ +{\ + Vector<Vector3> points;\ + points.resize(3);\ + points[0]=m_a;\ + points[1]=m_b;\ + points[2]=m_c;\ + Vector<Color> colors;\ + colors.resize(3);\ + colors[0]=m_color;\ + colors[1]=m_color;\ + colors[2]=m_color;\ + vs->poly_add_primitive(p_indicator,points,Vector<Vector3>(),colors,Vector<Vector3>());\ +} + + +void CollisionShape::_notification(int p_what) { + + switch (p_what) { + case NOTIFICATION_ENTER_SCENE: { + + + if (get_root_node()->get_editor() && !indicator.is_valid()) { + + indicator=VisualServer::get_singleton()->poly_create(); + RID mat=VisualServer::get_singleton()->fixed_material_create(); + VisualServer::get_singleton()->material_set_flag( mat, VisualServer::MATERIAL_FLAG_UNSHADED, true ); + VisualServer::get_singleton()->material_set_flag( mat, VisualServer::MATERIAL_FLAG_WIREFRAME, true ); + VisualServer::get_singleton()->material_set_flag( mat, VisualServer::MATERIAL_FLAG_DOUBLE_SIDED, true ); + VisualServer::get_singleton()->material_set_line_width( mat, 3 ); + + VisualServer::get_singleton()->poly_set_material(indicator,mat,true); + + update_indicator(indicator); + } + + if (indicator.is_valid()) { + + indicator_instance=VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario()); + VisualServer::get_singleton()->instance_attach_object_instance_ID(indicator_instance,get_instance_ID()); + } + volume_changed(); + } break; + case NOTIFICATION_EXIT_SCENE: { + + if (indicator_instance.is_valid()) { + + VisualServer::get_singleton()->free(indicator_instance); + } + volume_changed(); + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + if (indicator_instance.is_valid()) { + + VisualServer::get_singleton()->instance_set_transform(indicator_instance,get_global_transform()); + } + volume_changed(); + } break; + default: {} + } +} + +void CollisionShape::volume_changed() { + + if (indicator.is_valid()) + update_indicator(indicator); + + Object *parent=get_parent(); + if (!parent) + return; + PhysicsBody *physics_body=parent->cast_to<PhysicsBody>(); + + ERR_EXPLAIN("CollisionShape parent is not of type PhysicsBody"); + ERR_FAIL_COND(!physics_body); + + physics_body->recompute_child_volumes(); + +} + +RID CollisionShape::_get_visual_instance_rid() const { + + return indicator_instance; + +} + +void CollisionShape::_bind_methods() { + + ObjectTypeDB::bind_method("_get_visual_instance_rid",&CollisionShape::_get_visual_instance_rid); +} + +CollisionShape::CollisionShape() { + +} + +CollisionShape::~CollisionShape() { + + if (indicator.is_valid()) { + + VisualServer::get_singleton()->free(indicator); + } + +} + +void CollisionShapeSphere::_set(const String& p_name, const Variant& p_value) { + + if (p_name=="radius") { + radius=p_value; + volume_changed(); + } + +} + +Variant CollisionShapeSphere::_get(const String& p_name) const { + + if (p_name=="radius") { + return radius; + } + + return Variant(); +} + +void CollisionShapeSphere::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo(Variant::REAL,"radius",PROPERTY_HINT_RANGE,"0.01,16384,0.01") ); +} + +void CollisionShapeSphere::update_indicator(RID p_indicator) { + + VisualServer *vs=VisualServer::get_singleton(); + + vs->poly_clear(p_indicator); + Color col(0.4,1.0,1.0,0.5); + + int lats=6; + int lons=12; + float size=radius; + + for(int i = 1; i <= lats; i++) { + double lat0 = Math_PI * (-0.5 + (double) (i - 1) / lats); + double z0 = Math::sin(lat0); + double zr0 = Math::cos(lat0); + + double lat1 = Math_PI * (-0.5 + (double) i / lats); + double z1 = Math::sin(lat1); + double zr1 = Math::cos(lat1); + + for(int j = lons; j >= 1; j--) { + + double lng0 = 2 * Math_PI * (double) (j - 1) / lons; + double x0 = Math::cos(lng0); + double y0 = Math::sin(lng0); + + double lng1 = 2 * Math_PI * (double) (j) / lons; + double x1 = Math::cos(lng1); + double y1 = Math::sin(lng1); + + Vector3 v4=Vector3(x0 * zr0, z0, y0 *zr0)*size; + Vector3 v3=Vector3(x0 * zr1, z1, y0 *zr1)*size; + Vector3 v2=Vector3(x1 * zr1, z1, y1 *zr1)*size; + Vector3 v1=Vector3(x1 * zr0, z0, y1 *zr0)*size; + + Vector<Vector3> line; + line.push_back(v1); + line.push_back(v2); + line.push_back(v3); + line.push_back(v4); + + Vector<Color> cols; + cols.push_back(col); + cols.push_back(col); + cols.push_back(col); + cols.push_back(col); + + + VisualServer::get_singleton()->poly_add_primitive(p_indicator,line,Vector<Vector3>(),cols,Vector<Vector3>()); + } + } +} + +void CollisionShapeSphere::append_to_volume(Ref<Shape> p_volume) { + + p_volume->add_sphere_shape(radius,get_transform()); +} + + +CollisionShapeSphere::CollisionShapeSphere() { + + radius=1.0; +} + +/* BOX */ + + +void CollisionShapeBox::_set(const String& p_name, const Variant& p_value) { + + if (p_name=="half_extents") { + half_extents=p_value; + volume_changed(); + } + +} + +Variant CollisionShapeBox::_get(const String& p_name) const { + + if (p_name=="half_extents") { + return half_extents; + } + + return Variant(); +} + +void CollisionShapeBox::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo(Variant::VECTOR3,"half_extents" ) ); +} + + +void CollisionShapeBox::update_indicator(RID p_indicator) { + + VisualServer *vs=VisualServer::get_singleton(); + + vs->poly_clear(p_indicator); + Color col(0.4,1.0,1.0,0.5); + + + for (int i=0;i<6;i++) { + + + Vector3 face_points[4]; + + for (int j=0;j<4;j++) { + + float v[3]; + v[0]=1.0; + v[1]=1-2*((j>>1)&1); + v[2]=v[1]*(1-2*(j&1)); + + for (int k=0;k<3;k++) { + + if (i<3) + face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1); + else + face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1); + } + } + + for(int j=0;j<4;j++) + face_points[i]*=half_extents; + + ADD_TRIANGLE(face_points[0],face_points[1],face_points[2],col); + ADD_TRIANGLE(face_points[2],face_points[3],face_points[0],col); + + } +} + +void CollisionShapeBox::append_to_volume(Ref<Shape> p_volume) { + + p_volume->add_box_shape(half_extents,get_transform()); +} + + +CollisionShapeBox::CollisionShapeBox() { + + half_extents=Vector3(1,1,1); +} + +/* CYLINDER */ + + +void CollisionShapeCylinder::_set(const String& p_name, const Variant& p_value) { + + if (p_name=="radius") { + radius=p_value; + volume_changed(); + } + if (p_name=="height") { + height=p_value; + volume_changed(); + } + +} + +Variant CollisionShapeCylinder::_get(const String& p_name) const { + + if (p_name=="radius") { + return radius; + } + if (p_name=="height") { + return height; + } + return Variant(); +} + +void CollisionShapeCylinder::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo(Variant::REAL,"radius",PROPERTY_HINT_RANGE,"0.01,16384,0.01") ); + p_list->push_back( PropertyInfo(Variant::REAL,"height",PROPERTY_HINT_RANGE,"0.01,16384,0.01") ); +} + + +void CollisionShapeCylinder::update_indicator(RID p_indicator) { + + VisualServer *vs=VisualServer::get_singleton(); + + vs->poly_clear(p_indicator); + Color col(0.4,1.0,1.0,0.5); + + DVector<Plane> planes = Geometry::build_cylinder_planes(radius, height, 12, Vector3::AXIS_Z); + Geometry::MeshData md = Geometry::build_convex_mesh(planes); + + for(int i=0;i<md.faces.size();i++) { + + for(int j=2;j<md.faces[i].indices.size();j++) { + ADD_TRIANGLE(md.vertices[md.faces[i].indices[0]],md.vertices[md.faces[i].indices[j-1]],md.vertices[md.faces[i].indices[j]],col); + } + } + +} + +void CollisionShapeCylinder::append_to_volume(Ref<Shape> p_volume) { + + p_volume->add_cylinder_shape(radius,height*2.0,get_transform()); +} + + +CollisionShapeCylinder::CollisionShapeCylinder() { + + height=1; + radius=1; +} + +/* CAPSULE */ + + +void CollisionShapeCapsule::_set(const String& p_name, const Variant& p_value) { + + if (p_name=="radius") { + radius=p_value; + volume_changed(); + } + + if (p_name=="height") { + height=p_value; + volume_changed(); + } + +} + +Variant CollisionShapeCapsule::_get(const String& p_name) const { + + if (p_name=="radius") { + return radius; + } + if (p_name=="height") { + return height; + } + return Variant(); +} + +void CollisionShapeCapsule::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo(Variant::REAL,"radius",PROPERTY_HINT_RANGE,"0.01,16384,0.01") ); + p_list->push_back( PropertyInfo(Variant::REAL,"height",PROPERTY_HINT_RANGE,"0.01,16384,0.01") ); +} + + +void CollisionShapeCapsule::update_indicator(RID p_indicator) { + + VisualServer *vs=VisualServer::get_singleton(); + + vs->poly_clear(p_indicator); + Color col(0.4,1.0,1.0,0.5); + + DVector<Plane> planes = Geometry::build_capsule_planes(radius, height, 12, 3, Vector3::AXIS_Z); + Geometry::MeshData md = Geometry::build_convex_mesh(planes); + + for(int i=0;i<md.faces.size();i++) { + + for(int j=2;j<md.faces[i].indices.size();j++) { + ADD_TRIANGLE(md.vertices[md.faces[i].indices[0]],md.vertices[md.faces[i].indices[j-1]],md.vertices[md.faces[i].indices[j]],col); + } + } + +} + +void CollisionShapeCapsule::append_to_volume(Ref<Shape> p_volume) { + + + p_volume->add_capsule_shape(radius,height,get_transform()); +} + + +CollisionShapeCapsule::CollisionShapeCapsule() { + + height=1; + radius=1; +} +#endif diff --git a/scene/3d/body_shape.h b/scene/3d/body_shape.h new file mode 100644 index 0000000000..d1cb229f70 --- /dev/null +++ b/scene/3d/body_shape.h @@ -0,0 +1,80 @@ +/*************************************************************************/ +/* body_shape.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef COLLISION_SHAPE_H +#define COLLISION_SHAPE_H + +#include "scene/3d/spatial.h" +#include "scene/resources/shape.h" + +class CollisionShape : public Spatial { + + OBJ_TYPE( CollisionShape, Spatial ); + OBJ_CATEGORY("3D Physics Nodes"); + + RID _get_visual_instance_rid() const; + + Ref<Shape> shape; + + void _update_indicator(); + + RID material; + RID indicator; + RID indicator_instance; + + void resource_changed(RES res); + + bool updating_body; + bool trigger; + + void _update_body(); + void _add_to_collision_object(Object* p_cshape); +protected: + + void _notification(int p_what); + static void _bind_methods(); + +public: + + void make_convex_from_brothers(); + + void set_shape(const Ref<Shape> &p_shape); + Ref<Shape> get_shape() const; + + void set_updating_body(bool p_update); + bool is_updating_body() const; + + void set_trigger(bool p_trigger); + bool is_trigger() const; + + CollisionShape(); + ~CollisionShape(); +}; + +#endif // BODY_VOLUME_H + diff --git a/scene/3d/bone_attachment.cpp b/scene/3d/bone_attachment.cpp new file mode 100644 index 0000000000..cbc4abb7a9 --- /dev/null +++ b/scene/3d/bone_attachment.cpp @@ -0,0 +1,138 @@ +/*************************************************************************/ +/* bone_attachment.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "bone_attachment.h" + +bool BoneAttachment::_get(const StringName& p_name,Variant &r_ret) const { + + if (String(p_name)=="bone_name") { + + r_ret=get_bone_name(); + return true; + } + + return false; +} +bool BoneAttachment::_set(const StringName& p_name, const Variant& p_value){ + + if (String(p_name)=="bone_name") { + + set_bone_name(p_value); + return true; + } + + return false; +} +void BoneAttachment::_get_property_list( List<PropertyInfo>* p_list ) const{ + + Skeleton *parent=NULL; + if(get_parent()) + parent=get_parent()->cast_to<Skeleton>(); + + if (parent) { + + String names; + for(int i=0;i<parent->get_bone_count();i++) { + if(i>0) + names+=","; + names+=parent->get_bone_name(i); + } + + p_list->push_back(PropertyInfo(Variant::STRING,"bone_name",PROPERTY_HINT_ENUM,names)); + } else { + + p_list->push_back(PropertyInfo(Variant::STRING,"bone_name")); + + } + +} + + +void BoneAttachment::_check_bind() { + + if (get_parent() && get_parent()->cast_to<Skeleton>()) { + Skeleton *sk = get_parent()->cast_to<Skeleton>(); + int idx = sk->find_bone(bone_name); + if (idx!=-1) { + sk->bind_child_node_to_bone(idx,this);; + bound=true; + } + } +} + +void BoneAttachment::_check_unbind() { + + if (bound) { + + if (get_parent() && get_parent()->cast_to<Skeleton>()) { + Skeleton *sk = get_parent()->cast_to<Skeleton>(); + int idx = sk->find_bone(bone_name); + if (idx!=-1) { + sk->unbind_child_node_from_bone(idx,this);; + } + } + bound=false; + } +} + +void BoneAttachment::set_bone_name(const String& p_name) { + + if (is_inside_scene()) + _check_unbind(); + + bone_name=p_name; + + if (is_inside_scene()) + _check_bind(); +} + +String BoneAttachment::get_bone_name() const{ + + return bone_name; +} + +void BoneAttachment::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + _check_bind(); + } break; + case NOTIFICATION_EXIT_SCENE: { + + _check_unbind(); + } break; + } +} + +BoneAttachment::BoneAttachment() +{ + bound=false; + +} diff --git a/scene/3d/bone_attachment.h b/scene/3d/bone_attachment.h new file mode 100644 index 0000000000..5043b40fa8 --- /dev/null +++ b/scene/3d/bone_attachment.h @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* bone_attachment.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef BONE_ATTACHMENT_H +#define BONE_ATTACHMENT_H + +#include "scene/3d/skeleton.h" + +class BoneAttachment : public Spatial { + + OBJ_TYPE(BoneAttachment,Spatial); + + bool bound; + String bone_name; + + void _check_bind(); + void _check_unbind(); +protected: + + bool _get(const StringName& p_name,Variant &r_ret) const; + bool _set(const StringName& p_name, const Variant& p_value); + void _get_property_list( List<PropertyInfo>* p_list ) const; + void _notification(int p_what); + +public: + + void set_bone_name(const String& p_name); + String get_bone_name() const; + + BoneAttachment(); +}; + +#endif // BONE_ATTACHMENT_H diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp new file mode 100644 index 0000000000..ecdfc8a7f9 --- /dev/null +++ b/scene/3d/camera.cpp @@ -0,0 +1,727 @@ +/*************************************************************************/ +/* camera.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "camera.h" + +#include "camera_matrix.h" +#include "scene/resources/material.h" +#include "scene/resources/surface_tool.h" + + +void Camera::_update_audio_listener_state() { + + +} + +void Camera::_request_camera_update() { + + _update_camera(); +} + +void Camera::_update_camera_mode() { + + + force_change=true; + switch(mode) { + case PROJECTION_PERSPECTIVE: { + + + set_perspective(fov,near,far); + + } break; + case PROJECTION_ORTHOGONAL: { + set_orthogonal(size,near,far); + } break; + + } + +} + +bool Camera::_set(const StringName& p_name, const Variant& p_value) { + + bool changed_all=false; + if (p_name=="projection") { + + int proj = p_value; + if (proj==PROJECTION_PERSPECTIVE) + mode=PROJECTION_PERSPECTIVE; + if (proj==PROJECTION_ORTHOGONAL) + mode=PROJECTION_ORTHOGONAL; + + changed_all=true; + } else if (p_name=="fov") + fov=p_value; + else if (p_name=="size") + size=p_value; + else if (p_name=="near") + near=p_value; + else if (p_name=="far") + far=p_value; + else if (p_name=="vaspect") + set_use_vertical_aspect(p_value); + else if (p_name=="current") { + if (p_value.operator bool()) { + make_current(); + } else { + clear_current(); + } + } else if (p_name=="visible_layers") { + set_visible_layers(p_value); + } else if (p_name=="environment") { + set_environment(p_value); + } else + return false; + + _update_camera_mode(); + if (changed_all) + _change_notify(); + return true; + +} +bool Camera::_get(const StringName& p_name,Variant &r_ret) const { + + if (p_name=="projection") { + r_ret= mode; + } else if (p_name=="fov") + r_ret= fov; + else if (p_name=="size") + r_ret= size; + else if (p_name=="near") + r_ret= near; + else if (p_name=="far") + r_ret= far; + else if (p_name=="vaspect") + r_ret= vaspect; + else if (p_name=="current") { + + if (is_inside_scene() && get_scene()->is_editor_hint()) { + r_ret=current; + } else { + r_ret=is_current(); + } + } else if (p_name=="visible_layers") { + r_ret=get_visible_layers(); + } else if (p_name=="environment") { + r_ret=get_environment(); + } else + return false; + + return true; +} + +void Camera::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo( Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal") ); + + switch(mode) { + + case PROJECTION_PERSPECTIVE: { + + p_list->push_back( PropertyInfo( Variant::REAL, "fov" , PROPERTY_HINT_RANGE, "1,89,0.1") ); + + } break; + case PROJECTION_ORTHOGONAL: { + + p_list->push_back( PropertyInfo( Variant::REAL, "size" , PROPERTY_HINT_RANGE, "1,16384,0.01" ) ); + } break; + + } + + p_list->push_back( PropertyInfo( Variant::REAL, "near" , PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01") ); + p_list->push_back( PropertyInfo( Variant::REAL, "far" , PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "vaspect") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "current" ) ); + p_list->push_back( PropertyInfo( Variant::INT, "visible_layers",PROPERTY_HINT_ALL_FLAGS ) ); + p_list->push_back( PropertyInfo( Variant::OBJECT, "environment",PROPERTY_HINT_RESOURCE_TYPE,"Environment" ) ); + +} + +void Camera::_update_camera() { + + Transform tr = get_camera_transform(); + VisualServer::get_singleton()->camera_set_transform( camera, tr ); + +// here goes listener stuff +// if (viewport_ptr && is_inside_scene() && is_current()) +// viewport_ptr->_camera_transform_changed_notify(); + + if (is_inside_scene() && is_current()) { + if (viewport_ptr) { + viewport_ptr->_camera_transform_changed_notify(); + } + } + + if (is_current() && get_world().is_valid()) { + get_world()->_update_camera(this); + } + + +} + +void Camera::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_WORLD: { + + viewport_ptr=NULL; + + { //find viewport stuff + Node *parent=get_parent(); + + while(parent) { + + Viewport* viewport = parent->cast_to<Viewport>(); + + if (viewport) { + viewport_ptr=viewport; + break; + } + parent=parent->get_parent(); + } + + } + + if (viewport_ptr) + viewport_ptr->cameras.insert(this); + if (current) + make_current(); + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + _request_camera_update(); + } break; + case NOTIFICATION_EXIT_WORLD: { + + if (is_current()) { + clear_current(); + current=true; //keep it true + + } else { + current=false; + } + if (viewport_ptr) + viewport_ptr->cameras.erase(this); + viewport_ptr=NULL; + + } break; + case NOTIFICATION_BECAME_CURRENT: { + if (get_world().is_valid()) { + get_world()->_register_camera(this); + } + } break; + case NOTIFICATION_LOST_CURRENT: { + if (get_world().is_valid()) { + get_world()->_remove_camera(this); + } + } break; + + + } + +} + + +Transform Camera::get_camera_transform() const { + + return get_global_transform(); +} + +void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) { + + if (!force_change && fov==p_fovy_degrees && p_z_near==near && p_z_far==far && mode==PROJECTION_PERSPECTIVE) + return; + + fov=p_fovy_degrees; + near=p_z_near; + far=p_z_far; + mode=PROJECTION_PERSPECTIVE; + + VisualServer::get_singleton()->camera_set_perspective(camera,fov,near,far); + update_gizmo(); + force_change=false; +} +void Camera::set_orthogonal(float p_size, float p_z_near, float p_z_far) { + + if (!force_change && size==p_size && p_z_near==near && p_z_far==far && mode==PROJECTION_ORTHOGONAL) + return; + + size = p_size; + + near=p_z_near; + far=p_z_far; + mode=PROJECTION_ORTHOGONAL; + force_change=false; + + VisualServer::get_singleton()->camera_set_orthogonal(camera,size,near,far); + update_gizmo(); +} + +RID Camera::get_camera() const { + + return camera; +}; + +void Camera::make_current() { + + current=true; + + if (!is_inside_scene()) + return; + + if (viewport_ptr) { + viewport_ptr->_set_camera(this); + } + + //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this); +} + +void Camera::clear_current() { + + current=false; + if (!is_inside_scene()) + return; + + if (viewport_ptr) { + if (viewport_ptr->get_camera()==this) + viewport_ptr->_set_camera(NULL); + } + +} + +bool Camera::is_current() const { + + if (is_inside_scene()) { + if (viewport_ptr) + return viewport_ptr->get_camera()==this; + } else + return current; + + return false; +} + + +bool Camera::_can_gizmo_scale() const { + + return false; +} + + +RES Camera::_get_gizmo_geometry() const { + + + Ref<SurfaceTool> surface_tool( memnew( SurfaceTool )); + + Ref<FixedMaterial> mat( memnew( FixedMaterial )); + + mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(1.0,0.5,1.0,0.5) ); + mat->set_line_width(4); + mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); + mat->set_flag(Material::FLAG_UNSHADED,true); + mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true); + + surface_tool->begin(Mesh::PRIMITIVE_LINES); + surface_tool->set_material(mat); + + switch(mode) { + + case PROJECTION_PERSPECTIVE: { + + + + Vector3 side=Vector3( Math::sin(Math::deg2rad(fov)), 0, -Math::cos(Math::deg2rad(fov)) ); + Vector3 nside=side; + nside.x=-nside.x; + Vector3 up=Vector3(0,side.x,0); + + +#define ADD_TRIANGLE( m_a, m_b, m_c)\ +{\ + surface_tool->add_vertex(m_a);\ + surface_tool->add_vertex(m_b);\ + surface_tool->add_vertex(m_b);\ + surface_tool->add_vertex(m_c);\ + surface_tool->add_vertex(m_c);\ + surface_tool->add_vertex(m_a);\ +} + + ADD_TRIANGLE( Vector3(), side+up, side-up ); + ADD_TRIANGLE( Vector3(), nside+up, nside-up ); + ADD_TRIANGLE( Vector3(), side+up, nside+up ); + ADD_TRIANGLE( Vector3(), side-up, nside-up ); + + side.x*=0.25; + nside.x*=0.25; + Vector3 tup( 0, up.y*3/2,side.z); + ADD_TRIANGLE( tup, side+up, nside+up ); + + } break; + case PROJECTION_ORTHOGONAL: { + +#define ADD_QUAD( m_a, m_b, m_c, m_d)\ +{\ + surface_tool->add_vertex(m_a);\ + surface_tool->add_vertex(m_b);\ + surface_tool->add_vertex(m_b);\ + surface_tool->add_vertex(m_c);\ + surface_tool->add_vertex(m_c);\ + surface_tool->add_vertex(m_d);\ + surface_tool->add_vertex(m_d);\ + surface_tool->add_vertex(m_a);\ +} + + float hsize=size*0.5; + Vector3 right(hsize,0,0); + Vector3 up(0,hsize,0); + Vector3 back(0,0,-1.0); + Vector3 front(0,0,0); + + ADD_QUAD( -up-right,-up+right,up+right,up-right); + ADD_QUAD( -up-right+back,-up+right+back,up+right+back,up-right+back); + ADD_QUAD( up+right,up+right+back,up-right+back,up-right); + ADD_QUAD( -up+right,-up+right+back,-up-right+back,-up-right); + + right.x*=0.25; + Vector3 tup( 0, up.y*3/2,back.z ); + ADD_TRIANGLE( tup, right+up+back, -right+up+back ); + + } break; + + } + + return surface_tool->commit(); + +} + +Vector3 Camera::project_ray_normal(const Point2& p_pos) const { + + Vector3 ray = project_local_ray_normal(p_pos); + return get_camera_transform().basis.xform(ray).normalized(); +}; + +Vector3 Camera::project_local_ray_normal(const Point2& p_pos) const { + + if (!is_inside_scene()) { + ERR_EXPLAIN("Camera is not inside scene."); + ERR_FAIL_COND_V(!is_inside_scene(),Vector3()); + } + + Size2 viewport_size = viewport_ptr->get_visible_rect().size; + + Vector3 ray; + + if (mode==PROJECTION_ORTHOGONAL) { + + ray=Vector3(0,0,-1); + } else { + CameraMatrix cm; + cm.set_perspective(fov,viewport_size.get_aspect(),near,far,vaspect); + float screen_w,screen_h; + cm.get_viewport_size(screen_w,screen_h); + ray=Vector3( ((p_pos.x/viewport_size.width)*2.0-1.0)*screen_w, ((1.0-(p_pos.y/viewport_size.height))*2.0-1.0)*screen_h,-near).normalized(); + } + + + return ray; +}; + + +Vector3 Camera::project_ray_origin(const Point2& p_pos) const { + + if (!is_inside_scene()) { + ERR_EXPLAIN("Camera is not inside scene."); + ERR_FAIL_COND_V(!is_inside_scene(),Vector3()); + } + + Size2 viewport_size = viewport_ptr->get_visible_rect().size; + + + ERR_FAIL_COND_V( viewport_size.y == 0, Vector3() ); +// float aspect = viewport_size.x / viewport_size.y; + + if (mode == PROJECTION_PERSPECTIVE) { + + return get_camera_transform().origin; + } else { + + Vector2 pos = p_pos / viewport_size; + float vsize,hsize; + if (vaspect) { + vsize = size/viewport_size.get_aspect(); + hsize = size; + } else { + hsize = size*viewport_size.get_aspect(); + vsize = size; + + } + + Vector3 ray; + ray.x = pos.x * (hsize) - hsize/2; + ray.y = (1.0 - pos.y) * (vsize) - vsize/2; + ray.z = -near; + ray = get_camera_transform().xform(ray); + return ray; + }; +}; + +Point2 Camera::unproject_position(const Vector3& p_pos) const { + + if (!is_inside_scene()) { + ERR_EXPLAIN("Camera is not inside scene."); + ERR_FAIL_COND_V(!is_inside_scene(),Vector2()); + } + + Size2 viewport_size = viewport_ptr->get_visible_rect().size; + + CameraMatrix cm; + + + if (mode==PROJECTION_ORTHOGONAL) + cm.set_orthogonal(size,viewport_size.get_aspect(),near,far,vaspect); + else + cm.set_perspective(fov,viewport_size.get_aspect(),near,far,vaspect); + + Plane p(get_camera_transform().xform_inv(p_pos),1.0); + + p=cm.xform4(p); + p.normal/=p.d; + + + Point2 res; + res.x = (p.normal.x * 0.5 + 0.5) * viewport_size.x; + res.y = (-p.normal.y * 0.5 + 0.5) * viewport_size.y; + + return res; + +} + +Vector3 Camera::project_position(const Point2& p_point) const { + + if (!is_inside_scene()) { + ERR_EXPLAIN("Camera is not inside scene."); + ERR_FAIL_COND_V(!is_inside_scene(),Vector3()); + } + + Size2 viewport_size = viewport_ptr->get_visible_rect().size; + + CameraMatrix cm; + + if (mode==PROJECTION_ORTHOGONAL) + cm.set_orthogonal(size,viewport_size.get_aspect(),near,far,vaspect); + else + cm.set_perspective(fov,viewport_size.get_aspect(),near,far,vaspect); + + Size2 vp_size; + cm.get_viewport_size(vp_size.x,vp_size.y); + + Vector2 point; + point.x = (p_point.x/viewport_size.x) * 2.0 - 1.0; + point.y = (p_point.y/viewport_size.y) * 2.0 - 1.0; + point*=vp_size; + + Vector3 p(point.x,point.y,-near); + + + return get_camera_transform().xform(p); +} + +/* +void Camera::_camera_make_current(Node *p_camera) { + + + if (p_camera==this) { + VisualServer::get_singleton()->viewport_attach_camera(viewport_id,camera); + active=true; + } else { + if (active && p_camera==NULL) { + //detech camera because no one else will claim it + VisualServer::get_singleton()->viewport_attach_camera(viewport_id,RID()); + } + active=false; + } +} +*/ + +void Camera::set_environment(const Ref<Environment>& p_environment) { + + environment=p_environment; + if (environment.is_valid()) + VS::get_singleton()->camera_set_environment(camera,environment->get_rid()); + else + VS::get_singleton()->camera_set_environment(camera,RID()); +} + +Ref<Environment> Camera::get_environment() const { + + return environment; +} + + + +void Camera::_bind_methods() { + + ObjectTypeDB::bind_method( _MD("project_ray_normal","screen_point"), &Camera::project_ray_normal); + ObjectTypeDB::bind_method( _MD("project_local_ray_normal","screen_point"), &Camera::project_local_ray_normal); + ObjectTypeDB::bind_method( _MD("project_ray_origin","screen_point"), &Camera::project_ray_origin); + ObjectTypeDB::bind_method( _MD("unproject_position","world_point"), &Camera::unproject_position); + ObjectTypeDB::bind_method( _MD("project_position","screen_point"), &Camera::project_position); + ObjectTypeDB::bind_method( _MD("set_perspective","fov","z_near","z_far"),&Camera::set_perspective ); + ObjectTypeDB::bind_method( _MD("set_orthogonal","size","z_near","z_far"),&Camera::set_orthogonal ); + ObjectTypeDB::bind_method( _MD("make_current"),&Camera::make_current ); + ObjectTypeDB::bind_method( _MD("clear_current"),&Camera::clear_current ); + ObjectTypeDB::bind_method( _MD("is_current"),&Camera::is_current ); + ObjectTypeDB::bind_method( _MD("get_camera_transform"),&Camera::get_camera_transform ); + ObjectTypeDB::bind_method( _MD("get_fov"),&Camera::get_fov ); + ObjectTypeDB::bind_method( _MD("get_size"),&Camera::get_size ); + ObjectTypeDB::bind_method( _MD("get_zfar"),&Camera::get_zfar ); + ObjectTypeDB::bind_method( _MD("get_znear"),&Camera::get_znear ); + ObjectTypeDB::bind_method( _MD("get_projection"),&Camera::get_projection ); + ObjectTypeDB::bind_method( _MD("set_visible_layers","mask"),&Camera::set_visible_layers ); + ObjectTypeDB::bind_method( _MD("get_visible_layers"),&Camera::get_visible_layers ); + ObjectTypeDB::bind_method( _MD("look_at","target","up"),&Camera::look_at ); + ObjectTypeDB::bind_method( _MD("look_at_from_pos","pos","target","up"),&Camera::look_at_from_pos ); + ObjectTypeDB::bind_method(_MD("set_environment","env:Environment"),&Camera::set_environment); + ObjectTypeDB::bind_method(_MD("get_environment:Environment"),&Camera::get_environment); + ObjectTypeDB::bind_method(_MD("set_use_vertical_aspect","enable"),&Camera::set_use_vertical_aspect); + ObjectTypeDB::bind_method(_MD("is_using_vertical_aspect"),&Camera::is_using_vertical_aspect); + //ObjectTypeDB::bind_method( _MD("_camera_make_current"),&Camera::_camera_make_current ); + + BIND_CONSTANT( PROJECTION_PERSPECTIVE ); + BIND_CONSTANT( PROJECTION_ORTHOGONAL ); +} + +float Camera::get_fov() const { + + return fov; +} + +float Camera::get_size() const { + + return size; +} + +float Camera::get_znear() const { + + return near; +} + +float Camera::get_zfar() const { + + return far; +} + + +Camera::Projection Camera::get_projection() const { + + return mode; +} + +void Camera::set_visible_layers(uint32_t p_layers) { + + layers=p_layers; + VisualServer::get_singleton()->camera_set_visible_layers(camera,layers); +} + +uint32_t Camera::get_visible_layers() const{ + + return layers; +} + + +Vector<Plane> Camera::get_frustum() const { + + ERR_FAIL_COND_V(!is_inside_world(),Vector<Plane>()); + + Size2 viewport_size = viewport_ptr->get_visible_rect().size; + CameraMatrix cm; + if (mode==PROJECTION_PERSPECTIVE) + cm.set_perspective(fov,viewport_size.get_aspect(),near,far,vaspect); + else + cm.set_orthogonal(size,viewport_size.get_aspect(),near,far,vaspect); + + return cm.get_projection_planes(get_global_transform()); + +} + + +void Camera::set_use_vertical_aspect(bool p_enable) { + + vaspect=p_enable; + VisualServer::get_singleton()->camera_set_use_vertical_aspect(camera,p_enable); +} + + +bool Camera::is_using_vertical_aspect() const{ + + return vaspect; +} + +void Camera::look_at(const Vector3& p_target, const Vector3& p_up_normal) { + + Transform lookat; + lookat.origin=get_global_transform().origin; + lookat=lookat.looking_at(p_target,p_up_normal); + set_global_transform(lookat); +} + +void Camera::look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, const Vector3& p_up_normal) { + + Transform lookat; + lookat.origin=p_pos; + lookat=lookat.looking_at(p_target,p_up_normal); + set_global_transform(lookat); + +} + + +Camera::Camera() { + + camera = VisualServer::get_singleton()->camera_create(); + size=1; + fov=0; + near=0; + far=0; + current=false; + viewport_ptr=NULL; + force_change=false; + mode=PROJECTION_PERSPECTIVE; + set_perspective(60.0,0.1,100.0); + vaspect=false; + layers=0xFFFFFFFF; + //active=false; +} + + +Camera::~Camera() { + + VisualServer::get_singleton()->free(camera); + +} + + diff --git a/scene/3d/camera.h b/scene/3d/camera.h new file mode 100644 index 0000000000..a8599497ac --- /dev/null +++ b/scene/3d/camera.h @@ -0,0 +1,144 @@ +/*************************************************************************/ +/* camera.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef CAMERA_H +#define CAMERA_H + + +#include "scene/3d/spatial.h" +#include "scene/main/viewport.h" +#include "scene/resources/environment.h" +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class Camera : public Spatial { + + OBJ_TYPE( Camera, Spatial ); +public: + enum Projection { + + PROJECTION_PERSPECTIVE, + PROJECTION_ORTHOGONAL + }; + +private: + + bool force_change; + bool current; + + Projection mode; + + float fov; + float size; + float near,far; + bool vaspect; + + RID camera; + RID scenario_id; + + uint32_t layers; + + Viewport *viewport_ptr; + Ref<Environment> environment; + + virtual bool _can_gizmo_scale() const; + virtual RES _get_gizmo_geometry() const; + + + + //void _camera_make_current(Node *p_camera); +friend class Viewport; + void _update_audio_listener_state(); +protected: + + void _update_camera(); + virtual void _request_camera_update(); + void _update_camera_mode(); + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + void _notification(int p_what); + + static void _bind_methods(); + +public: + + enum { + + NOTIFICATION_BECAME_CURRENT=50, + NOTIFICATION_LOST_CURRENT=51 + }; + + void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far); + void set_orthogonal(float p_size, float p_z_near, float p_z_far); + + void make_current(); + void clear_current(); + bool is_current() const; + + RID get_camera() const; + + float get_fov() const; + float get_size() const; + float get_zfar() const; + float get_znear() const; + Projection get_projection() const; + + virtual Transform get_camera_transform() const; + + Vector3 project_ray_normal(const Point2& p_point) const; + Vector3 project_ray_origin(const Point2& p_point) const; + Vector3 project_local_ray_normal(const Point2& p_point) const; + Point2 unproject_position(const Vector3& p_pos) const; + Vector3 project_position(const Point2& p_point) const; + + void set_visible_layers(uint32_t p_layers); + uint32_t get_visible_layers() const; + + Vector<Plane> get_frustum() const; + + void set_environment(const Ref<Environment>& p_environment); + Ref<Environment> get_environment() const; + + void set_use_vertical_aspect(bool p_enable); + bool is_using_vertical_aspect() const; + + void look_at(const Vector3& p_target, const Vector3& p_up_normal); + void look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, const Vector3& p_up_normal); + + + Camera(); + ~Camera(); + +}; + + +VARIANT_ENUM_CAST( Camera::Projection ); + +#endif diff --git a/scene/3d/car_body.cpp b/scene/3d/car_body.cpp new file mode 100644 index 0000000000..a21598b07c --- /dev/null +++ b/scene/3d/car_body.cpp @@ -0,0 +1,741 @@ +/*************************************************************************/ +/* car_body.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "car_body.h" + +#define DEG2RADMUL (Math_PI/180.0) +#define RAD2DEGMUL (180.0/Math_PI) + +void CarWheel::_notification(int p_what) { + + + if (p_what==NOTIFICATION_ENTER_SCENE) { + + if (!get_parent()) + return; + CarBody *cb = get_parent()->cast_to<CarBody>(); + if (!cb) + return; + body=cb; + local_xform=get_transform(); + cb->wheels.push_back(this); + } + if (p_what==NOTIFICATION_EXIT_SCENE) { + + if (!get_parent()) + return; + CarBody *cb = get_parent()->cast_to<CarBody>(); + if (!cb) + return; + cb->wheels.erase(this); + body=NULL; + } +} + +void CarWheel::set_side_friction(real_t p_friction) { + + side_friction=p_friction; +} +void CarWheel::set_forward_friction(real_t p_friction) { + + forward_friction=p_friction; +} +void CarWheel::set_travel(real_t p_travel) { + + travel=p_travel; + update_gizmo(); + +} +void CarWheel::set_radius(real_t p_radius) { + + radius=p_radius; + update_gizmo(); + +} +void CarWheel::set_resting_frac(real_t p_frac) { + + resting_frac=p_frac; +} +void CarWheel::set_damping_frac(real_t p_frac) { + + damping_frac=p_frac; +} +void CarWheel::set_num_rays(real_t p_rays) { + + num_rays=p_rays; +} + +real_t CarWheel::get_side_friction() const{ + + return side_friction; +} +real_t CarWheel::get_forward_friction() const{ + + return forward_friction; +} +real_t CarWheel::get_travel() const{ + + return travel; +} +real_t CarWheel::get_radius() const{ + + return radius; +} +real_t CarWheel::get_resting_frac() const{ + + return resting_frac; +} +real_t CarWheel::get_damping_frac() const{ + + return damping_frac; +} + +int CarWheel::get_num_rays() const{ + + return num_rays; +} + + +void CarWheel::update(real_t dt) { + + + if (dt <= 0.0f) + return; + + float origAngVel = angVel; + + if (locked) + { + angVel = 0; + torque = 0; + } + else + { + + float wheelMass = 0.03f * body->mass; + float inertia = 0.5f * (radius * radius) * wheelMass; + + angVel += torque * dt / inertia; + torque = 0; + + // prevent friction from reversing dir - todo do this better + // by limiting the torque + if (((origAngVel > angVelForGrip) && (angVel < angVelForGrip)) || + ((origAngVel < angVelForGrip) && (angVel > angVelForGrip))) + angVel = angVelForGrip; + + angVel += driveTorque * dt / inertia; + driveTorque = 0; + + float maxAngVel = 200; + print_line("angvel: "+rtos(angVel)); + angVel = CLAMP(angVel, -maxAngVel, maxAngVel); + + axisAngle += Math::rad2deg(dt * angVel); + } +} + +bool CarWheel::add_forces(PhysicsDirectBodyState *s) { + + + Vector3 force; + + PhysicsDirectSpaceState *space = s->get_space_state(); + + Transform world = s->get_transform() * local_xform; + + // OpenGl has differnet row/column order for matrixes than XNA has .. + //Vector3 wheelFwd = world.get_basis().get_axis(Vector3::AXIS_Z); + //Vector3 wheelFwd = RotationMatrix(mSteerAngle, worldAxis) * carBody.GetOrientation().GetCol(0); + Vector3 wheelUp = world.get_basis().get_axis(Vector3::AXIS_Y); + Vector3 wheelFwd = Matrix3(wheelUp,Math::deg2rad(steerAngle)).xform( world.get_basis().get_axis(Vector3::AXIS_Z) ); + Vector3 wheelLeft = -wheelUp.cross(wheelFwd).normalized(); + Vector3 worldPos = world.origin; + Vector3 worldAxis = wheelUp; + + // start of ray + float rayLen = 2.0f * radius + travel; + Vector3 wheelRayEnd = worldPos - radius * worldAxis; + Vector3 wheelRayBegin = wheelRayEnd + rayLen * worldAxis; + //wheelRayEnd = -rayLen * worldAxis; + + //Assert(PhysicsSystem.CurrentPhysicsSystem); + + + ///Assert(collSystem); + /// + const int maxNumRays = 32; + + int numRaysUse = MIN(num_rays, maxNumRays); + + // adjust the start position of the ray - divide the wheel into numRays+2 + // rays, but don't use the first/last. + float deltaFwd = (2.0f * radius) / (numRaysUse + 1); + float deltaFwdStart = deltaFwd; + + float fracs[maxNumRays]; + Vector3 segmentEnds[maxNumRays]; + Vector3 groundPositions[maxNumRays]; + Vector3 groundNormals[maxNumRays]; + + + lastOnFloor = false; + int bestIRay = 0; + int iRay; + + + for (iRay = 0; iRay < numRaysUse; ++iRay) + { + fracs[iRay] = 1e20; + // work out the offset relative to the middle ray + float distFwd = (deltaFwdStart + iRay * deltaFwd) - radius; + float zOffset = radius * (1.0f - (float)Math::cos( Math::deg2rad( 90.0f * (distFwd / radius)))); + + segmentEnds[iRay] = wheelRayEnd + distFwd * wheelFwd + zOffset * wheelUp; + + + PhysicsDirectSpaceState::RayResult rr; + + bool collided = space->intersect_ray(wheelRayBegin,segmentEnds[iRay],rr,body->exclude); + + + if (collided){ + lastOnFloor = true; + groundPositions[iRay]=rr.position; + groundNormals[iRay]=rr.normal; + fracs[iRay] = ((wheelRayBegin-rr.position).length() / (wheelRayBegin-wheelRayEnd).length()); + if (fracs[iRay] < fracs[bestIRay]) + bestIRay = iRay; + } + } + + + if (!lastOnFloor) + return false; + + //Assert(bestIRay < numRays); + + // use the best one + Vector3 groundPos = groundPositions[bestIRay]; + float frac = fracs[bestIRay]; + + // const Vector3 groundNormal = (worldPos - segments[bestIRay].GetEnd()).NormaliseSafe(); + // const Vector3 groundNormal = groundNormals[bestIRay]; + + + Vector3 groundNormal = worldAxis; + + if (numRaysUse > 1) + { + for (iRay = 0; iRay < numRaysUse; ++iRay) + { + if (fracs[iRay] <= 1.0f) + { + groundNormal += (1.0f - fracs[iRay]) * (worldPos - segmentEnds[iRay]); + } + } + + groundNormal.normalize(); + + } + else + { + groundNormal = groundNormals[bestIRay]; + } + + + + float spring = (body->mass/body->wheels.size()) * s->get_total_gravity().length() / (resting_frac * travel); + + float displacement = rayLen * (1.0f - frac); + displacement = CLAMP(displacement, 0, travel); + + + + float displacementForceMag = displacement * spring; + + // reduce force when suspension is par to ground + displacementForceMag *= groundNormals[bestIRay].dot(worldAxis); + + // apply damping + float damping = 2.0f * (float)Math::sqrt(spring * body->mass); + damping /= body->wheels.size(); // assume wheels act together + damping *= damping_frac; // a bit bouncy + + float upSpeed = (displacement - lastDisplacement) / s->get_step(); + + float dampingForceMag = upSpeed * damping; + + float totalForceMag = displacementForceMag + dampingForceMag; + + if (totalForceMag < 0.0f) totalForceMag = 0.0f; + + Vector3 extraForce = totalForceMag * worldAxis; + + + force += extraForce; + // side-slip friction and drive force. Work out wheel- and floor-relative coordinate frame + Vector3 groundUp = groundNormal; + Vector3 groundLeft = groundNormal.cross(wheelFwd).normalized(); + + Vector3 groundFwd = groundLeft.cross(groundUp); + + Vector3 wheelPointVel = s->get_linear_velocity() + + (s->get_angular_velocity()).cross(s->get_transform().basis.xform(local_xform.origin));// * mPos); + + Vector3 rimVel = -angVel * wheelLeft.cross(groundPos - worldPos); + wheelPointVel += rimVel; + + // if sitting on another body then adjust for its velocity. + /*if (worldBody != null) + { + Vector3 worldVel = worldBody.Velocity + + Vector3.Cross(worldBody.AngularVelocity, groundPos - worldBody.Position); + + wheelPointVel -= worldVel; + }*/ + + // sideways forces + float noslipVel = 0.2f; + float slipVel = 0.4f; + float slipFactor = 0.7f; + + float smallVel = 3; + float friction = side_friction; + + float sideVel = wheelPointVel.dot(groundLeft); + + if ((sideVel > slipVel) || (sideVel < -slipVel)) + friction *= slipFactor; + else + if ((sideVel > noslipVel) || (sideVel < -noslipVel)) + friction *= 1.0f - (1.0f - slipFactor) * (Math::absf(sideVel) - noslipVel) / (slipVel - noslipVel); + + if (sideVel < 0.0f) + friction *= -1.0f; + + if (Math::absf(sideVel) < smallVel) + friction *= Math::absf(sideVel) / smallVel; + + float sideForce = -friction * totalForceMag; + + extraForce = sideForce * groundLeft; + force += extraForce; + // fwd/back forces + friction = forward_friction; + float fwdVel = wheelPointVel.dot(groundFwd); + + if ((fwdVel > slipVel) || (fwdVel < -slipVel)) + friction *= slipFactor; + else + if ((fwdVel > noslipVel) || (fwdVel < -noslipVel)) + friction *= 1.0f - (1.0f - slipFactor) * (Math::absf(fwdVel) - noslipVel) / (slipVel - noslipVel); + + if (fwdVel < 0.0f) + friction *= -1.0f; + + if (Math::absf(fwdVel) < smallVel) + friction *= Math::absf(fwdVel) / smallVel; + + float fwdForce = -friction * totalForceMag; + + extraForce = fwdForce * groundFwd; + force += extraForce; + + + //if (!force.IsSensible()) + //{ + // TRACE_FILE_IF(ONCE_1) + // TRACE("Bad force in car wheel\n"); + // return true; + //} + + // fwd force also spins the wheel + Vector3 wheelCentreVel = s->get_linear_velocity() + + (s->get_angular_velocity()).cross(s->get_transform().basis.xform(local_xform.origin)); + + angVelForGrip = wheelCentreVel.dot(groundFwd) / radius; + torque += -fwdForce * radius; + + // add force to car +// carBody.AddWorldForce(force, groundPos); + + s->add_force(force,(groundPos-s->get_transform().origin)); + + // add force to the world + /* + if (worldBody != null && !worldBody.Immovable) + { + // todo get the position in the right place... + // also limit the velocity that this force can produce by looking at the + // mass/inertia of the other object + float maxOtherBodyAcc = 500.0f; + float maxOtherBodyForce = maxOtherBodyAcc * worldBody.Mass; + + if (force.LengthSquared() > (maxOtherBodyForce * maxOtherBodyForce)) + force *= maxOtherBodyForce / force.Length(); + + worldBody.AddWorldForce(-force, groundPos); + }*/ + + Transform wheel_xf = local_xform; + wheel_xf.origin += wheelUp * displacement; + wheel_xf.basis = wheel_xf.basis * Matrix3(Vector3(0,1,0),Math::deg2rad(steerAngle)); + //wheel_xf.basis = wheel_xf.basis * Matrix3(wheel_xf.basis[0],-Math::deg2rad(axisAngle)); + + set_transform(wheel_xf); + lastDisplacement=displacement; + return true; + +} + +void CarWheel::set_type_drive(bool p_enable) { + + type_drive=p_enable; +} + +bool CarWheel::is_type_drive() const { + + return type_drive; +} + +void CarWheel::set_type_steer(bool p_enable) { + + type_steer=p_enable; +} + +bool CarWheel::is_type_steer() const { + + return type_steer; +} + + +void CarWheel::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_side_friction","friction"),&CarWheel::set_side_friction); + ObjectTypeDB::bind_method(_MD("set_forward_friction","friction"),&CarWheel::set_forward_friction); + ObjectTypeDB::bind_method(_MD("set_travel","distance"),&CarWheel::set_travel); + ObjectTypeDB::bind_method(_MD("set_radius","radius"),&CarWheel::set_radius); + ObjectTypeDB::bind_method(_MD("set_resting_frac","frac"),&CarWheel::set_resting_frac); + ObjectTypeDB::bind_method(_MD("set_damping_frac","frac"),&CarWheel::set_damping_frac); + ObjectTypeDB::bind_method(_MD("set_num_rays","amount"),&CarWheel::set_num_rays); + + ObjectTypeDB::bind_method(_MD("get_side_friction"),&CarWheel::get_side_friction); + ObjectTypeDB::bind_method(_MD("get_forward_friction"),&CarWheel::get_forward_friction); + ObjectTypeDB::bind_method(_MD("get_travel"),&CarWheel::get_travel); + ObjectTypeDB::bind_method(_MD("get_radius"),&CarWheel::get_radius); + ObjectTypeDB::bind_method(_MD("get_resting_frac"),&CarWheel::get_resting_frac); + ObjectTypeDB::bind_method(_MD("get_damping_frac"),&CarWheel::get_damping_frac); + ObjectTypeDB::bind_method(_MD("get_num_rays"),&CarWheel::get_num_rays); + + ObjectTypeDB::bind_method(_MD("set_type_drive","enable"),&CarWheel::set_type_drive); + ObjectTypeDB::bind_method(_MD("is_type_drive"),&CarWheel::is_type_drive); + + ObjectTypeDB::bind_method(_MD("set_type_steer","enable"),&CarWheel::set_type_steer); + ObjectTypeDB::bind_method(_MD("is_type_steer"),&CarWheel::is_type_steer); + + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"type/drive"),_SCS("set_type_drive"),_SCS("is_type_drive")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"type/steer"),_SCS("set_type_steer"),_SCS("is_type_steer")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/side_friction",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_side_friction"),_SCS("get_side_friction")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/forward_friction",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_forward_friction"),_SCS("get_forward_friction")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/travel",PROPERTY_HINT_RANGE,"0.01,1024,0.01"),_SCS("set_travel"),_SCS("get_travel")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/radius",PROPERTY_HINT_RANGE,"0.01,1024,0.01"),_SCS("set_radius"),_SCS("get_radius")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/resting_frac",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_resting_frac"),_SCS("get_resting_frac")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/damping_frac",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_damping_frac"),_SCS("get_damping_frac")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/num_rays",PROPERTY_HINT_RANGE,"1,32,1"),_SCS("set_num_rays"),_SCS("get_num_rays")); + +} + +CarWheel::CarWheel() { + + side_friction=4.7; + forward_friction=5.0; + travel=0.2; + radius=0.4; + resting_frac=0.45; + damping_frac=0.3; + num_rays=1; + + angVel = 0.0f; + steerAngle = 0.0f; + torque = 0.0f; + driveTorque = 0.0f; + axisAngle = 0.0f; + upSpeed = 0.0f; + locked = false; + lastDisplacement = 0.0f; + lastOnFloor = false; + angVelForGrip = 0.0f; + angVelForGrip=0; + + type_drive=false; + type_steer=false; + +} + +/// + + +void CarBody::set_max_steer_angle(real_t p_angle) { + + max_steer_angle=p_angle; +} +void CarBody::set_steer_rate(real_t p_rate) { + + steer_rate=p_rate; +} +void CarBody::set_drive_torque(real_t p_torque) { + + drive_torque=p_torque; +} + +real_t CarBody::get_max_steer_angle() const{ + + return max_steer_angle; +} +real_t CarBody::get_steer_rate() const{ + + return steer_rate; +} +real_t CarBody::get_drive_torque() const{ + + return drive_torque; +} + + +void CarBody::set_target_steering(float p_steering) { + + target_steering=p_steering; +} + +void CarBody::set_target_accelerate(float p_accelerate) { + target_accelerate=p_accelerate; +} + +void CarBody::set_hand_brake(float p_amont) { + + hand_brake=p_amont; +} + +real_t CarBody::get_target_steering() const { + + return target_steering; +} +real_t CarBody::get_target_accelerate() const { + + return target_accelerate; +} +real_t CarBody::get_hand_brake() const { + + return hand_brake; +} + + +void CarBody::_direct_state_changed(Object *p_state) { + + PhysicsDirectBodyState *state=p_state->cast_to<PhysicsDirectBodyState>(); + + float dt = state->get_step(); + AABB aabb; + int drive_total=0; + for(int i=0;i<wheels.size();i++) { + CarWheel *w=wheels[i]; + if (i==0) { + aabb.pos=w->local_xform.origin; + } else { + aabb.expand_to(w->local_xform.origin); + } + if (w->type_drive) + drive_total++; + + } + // control inputs + float deltaAccelerate = dt * 4.0f; + + float dAccelerate = target_accelerate - accelerate; + dAccelerate = CLAMP(dAccelerate, -deltaAccelerate, deltaAccelerate); + accelerate += dAccelerate; + + float deltaSteering = dt * steer_rate; + float dSteering = target_steering - steering; + dSteering = CLAMP(dSteering, -deltaSteering, deltaSteering); + steering += dSteering; + + // apply these inputs + float maxTorque = drive_torque; + + float torque_div = drive_total/2; + if (torque_div>0) + maxTorque/=torque_div; + + + float alpha = ABS(max_steer_angle * steering); + float angleSgn = steering > 0.0f ? 1.0f : -1.0f; + + int wheels_on_floor=0; + + for(int i=0;i<wheels.size();i++) { + + CarWheel *w=wheels[i]; + if (w->type_drive) + w->driveTorque+=maxTorque * accelerate; + w->locked = !w->type_steer && (hand_brake > 0.5f); + + if (w->type_steer) { + //steering + + bool inner = (steering > 0 && w->local_xform.origin.x > 0) || (steering < 0 && w->local_xform.origin.x < 0); + + if (inner || alpha==0.0) { + + w->steerAngle = (angleSgn * alpha); + } else { + float dx = aabb.size.z; + float dy = aabb.size.x; + + float beta = Math::atan2(dy, dx + (dy / (float)Math::tan(Math::deg2rad(alpha)))); + beta = Math::rad2deg(beta); + w->steerAngle = (angleSgn * beta); + + } + } + + if (w->add_forces(state)) + wheels_on_floor++; + w->update(dt); + + + } + + print_line("onfloor: "+itos(wheels_on_floor)); + + + set_ignore_transform_notification(true); + set_global_transform(state->get_transform()); + linear_velocity=state->get_linear_velocity(); + angular_velocity=state->get_angular_velocity(); + //active=!state->is_sleeping(); + //if (get_script_instance()) + // get_script_instance()->call("_integrate_forces",state); + set_ignore_transform_notification(false); + + +} + +void CarBody::set_mass(real_t p_mass) { + + mass=p_mass; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_MASS,mass); +} + +real_t CarBody::get_mass() const{ + + return mass; +} + + +void CarBody::set_friction(real_t p_friction) { + + friction=p_friction; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_FRICTION,friction); +} + +real_t CarBody::get_friction() const{ + + return friction; +} + + +void CarBody::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_max_steer_angle","value"),&CarBody::set_max_steer_angle); + ObjectTypeDB::bind_method(_MD("set_steer_rate","rate"),&CarBody::set_steer_rate); + ObjectTypeDB::bind_method(_MD("set_drive_torque","value"),&CarBody::set_drive_torque); + + ObjectTypeDB::bind_method(_MD("get_max_steer_angle"),&CarBody::get_max_steer_angle); + ObjectTypeDB::bind_method(_MD("get_steer_rate"),&CarBody::get_steer_rate); + ObjectTypeDB::bind_method(_MD("get_drive_torque"),&CarBody::get_drive_torque); + + ObjectTypeDB::bind_method(_MD("set_target_steering","amount"),&CarBody::set_target_steering); + ObjectTypeDB::bind_method(_MD("set_target_accelerate","amount"),&CarBody::set_target_accelerate); + ObjectTypeDB::bind_method(_MD("set_hand_brake","amount"),&CarBody::set_hand_brake); + + ObjectTypeDB::bind_method(_MD("get_target_steering"),&CarBody::get_target_steering); + ObjectTypeDB::bind_method(_MD("get_target_accelerate"),&CarBody::get_target_accelerate); + ObjectTypeDB::bind_method(_MD("get_hand_brake"),&CarBody::get_hand_brake); + + ObjectTypeDB::bind_method(_MD("set_mass","mass"),&CarBody::set_mass); + ObjectTypeDB::bind_method(_MD("get_mass"),&CarBody::get_mass); + + ObjectTypeDB::bind_method(_MD("set_friction","friction"),&CarBody::set_friction); + ObjectTypeDB::bind_method(_MD("get_friction"),&CarBody::get_friction); + + ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&CarBody::_direct_state_changed); + + ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/mass",PROPERTY_HINT_RANGE,"0.01,65536,0.01"),_SCS("set_mass"),_SCS("get_mass")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/friction",PROPERTY_HINT_RANGE,"0.01,1,0.01"),_SCS("set_friction"),_SCS("get_friction")); + + ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/max_steer_angle",PROPERTY_HINT_RANGE,"1,90,1"),_SCS("set_max_steer_angle"),_SCS("get_max_steer_angle")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/drive_torque",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_drive_torque"),_SCS("get_drive_torque")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/steer_rate",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_steer_rate"),_SCS("get_steer_rate")); + + ADD_PROPERTY( PropertyInfo(Variant::REAL,"drive/target_steering",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_target_steering"),_SCS("get_target_steering")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"drive/target_accelerate",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_target_accelerate"),_SCS("get_target_accelerate")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"drive/hand_brake",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_hand_brake"),_SCS("get_hand_brake")); + +} + +CarBody::CarBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) { + + forward_drive=true; + backward_drive=true; + max_steer_angle=30; + steer_rate=1; + drive_torque=520; + + target_steering=0; + target_accelerate=0; + hand_brake=0; + + steering=0; + accelerate=0; + + mass=1; + friction=1; + + ccd=false; +// can_sleep=true; + + + + + exclude.insert(get_rid()); + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_direct_state_changed"); + + +} diff --git a/scene/3d/car_body.h b/scene/3d/car_body.h new file mode 100644 index 0000000000..87eb047bcf --- /dev/null +++ b/scene/3d/car_body.h @@ -0,0 +1,170 @@ +/*************************************************************************/ +/* car_body.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef CAR_BODY_H +#define CAR_BODY_H + +#include "scene/3d/physics_body.h" + + +class CarBody; + +class CarWheel : public Spatial { + + OBJ_TYPE(CarWheel,Spatial); + +friend class CarBody; + real_t side_friction; + real_t forward_friction; + real_t travel; + real_t radius; + real_t resting_frac; + real_t damping_frac; + int num_rays; + Transform local_xform; + + CarBody *body; + + float angVel; + float steerAngle; + float torque; + float driveTorque; + float axisAngle; + float upSpeed; // speed relative to the car + bool locked; + // last frame stuff + float lastDisplacement; + float angVelForGrip; + bool lastOnFloor; + + bool type_drive; + bool type_steer; + + +protected: + void update(real_t dt); + bool add_forces(PhysicsDirectBodyState *s); + void _notification(int p_what); + static void _bind_methods(); + +public: + + void set_side_friction(real_t p_friction); + void set_forward_friction(real_t p_friction); + void set_travel(real_t p_travel); + void set_radius(real_t p_radius); + void set_resting_frac(real_t p_frac); + void set_damping_frac(real_t p_frac); + void set_num_rays(real_t p_rays); + + real_t get_side_friction() const; + real_t get_forward_friction() const; + real_t get_travel() const; + real_t get_radius() const; + real_t get_resting_frac() const; + real_t get_damping_frac() const; + int get_num_rays() const; + + void set_type_drive(bool p_enable); + bool is_type_drive() const; + + void set_type_steer(bool p_enable); + bool is_type_steer() const; + + CarWheel(); + +}; + + + +class CarBody : public PhysicsBody { + + OBJ_TYPE(CarBody,PhysicsBody); + + real_t mass; + real_t friction; + + Vector3 linear_velocity; + Vector3 angular_velocity; + bool ccd; + + real_t max_steer_angle; + real_t steer_rate; + int wheel_num_rays; + real_t drive_torque; + +// control stuff + real_t target_steering; + real_t target_accelerate; + + bool forward_drive; + bool backward_drive; + + real_t steering; + real_t accelerate; + real_t hand_brake; + Set<RID> exclude; + + +friend class CarWheel; + Vector<CarWheel*> wheels; + + static void _bind_methods(); + + void _direct_state_changed(Object *p_state); +public: + + + void set_mass(real_t p_mass); + real_t get_mass() const; + + void set_friction(real_t p_friction); + real_t get_friction() const; + + void set_max_steer_angle(real_t p_angle); + void set_steer_rate(real_t p_rate); + void set_drive_torque(real_t p_torque); + + real_t get_max_steer_angle() const; + real_t get_steer_rate() const; + real_t get_drive_torque() const; + + + void set_target_steering(float p_steering); + void set_target_accelerate(float p_accelerate); + void set_hand_brake(float p_amont); + + real_t get_target_steering() const; + real_t get_target_accelerate() const; + real_t get_hand_brake() const; + + + CarBody(); +}; + +#endif // CAR_BODY_H diff --git a/scene/3d/character_camera.cpp b/scene/3d/character_camera.cpp new file mode 100644 index 0000000000..e3c071d42f --- /dev/null +++ b/scene/3d/character_camera.cpp @@ -0,0 +1,718 @@ +/*************************************************************************/ +/* character_camera.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "character_camera.h" + +#include "physics_body.h" +#if 0 +void CharacterCamera::_set(const String& p_name, const Variant& p_value) { + + if (p_name=="type") + set_camera_type((CameraType)((int)(p_value))); + else if (p_name=="orbit") + set_orbit(p_value); + else if (p_name=="height") + set_height(p_value); + else if (p_name=="inclination") + set_inclination(p_value); + else if (p_name=="max_orbit_x") + set_max_orbit_x(p_value); + else if (p_name=="min_orbit_x") + set_min_orbit_x(p_value); + else if (p_name=="max_distance") + set_max_distance(p_value); + else if (p_name=="min_distance") + set_min_distance(p_value); + else if (p_name=="distance") + set_distance(p_value); + else if (p_name=="clip") + set_clip(p_value); + else if (p_name=="autoturn") + set_autoturn(p_value); + else if (p_name=="autoturn_tolerance") + set_autoturn_tolerance(p_value); + else if (p_name=="autoturn_speed") + set_autoturn_speed(p_value); + +} +Variant CharacterCamera::_get(const String& p_name) const { + + if (p_name=="type") + return get_camera_type(); + else if (p_name=="orbit") + return get_orbit(); + else if (p_name=="height") + return get_height(); + else if (p_name=="inclination") + return get_inclination(); + else if (p_name=="max_orbit_x") + return get_max_orbit_x(); + else if (p_name=="min_orbit_x") + return get_min_orbit_x(); + else if (p_name=="max_distance") + return get_max_distance(); + else if (p_name=="min_distance") + return get_min_distance(); + else if (p_name=="distance") + return get_distance(); + else if (p_name=="clip") + return has_clip(); + else if (p_name=="autoturn") + return has_autoturn(); + else if (p_name=="autoturn_tolerance") + return get_autoturn_tolerance(); + else if (p_name=="autoturn_speed") + return get_autoturn_speed(); + + return Variant(); +} + +void CharacterCamera::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo( Variant::INT, "type", PROPERTY_HINT_ENUM, "Fixed,Follow") ); + p_list->push_back( PropertyInfo( Variant::VECTOR2, "orbit" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "height", PROPERTY_HINT_RANGE,"-1024,1024,0.01" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "inclination", PROPERTY_HINT_RANGE,"-90,90,0.01" ) ); ; + p_list->push_back( PropertyInfo( Variant::REAL, "max_orbit_x", PROPERTY_HINT_RANGE,"-90,90,0.01" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "min_orbit_x", PROPERTY_HINT_RANGE,"-90,90,0.01" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "min_distance", PROPERTY_HINT_RANGE,"0,100,0.01" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "max_distance", PROPERTY_HINT_RANGE,"0,100,0.01" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "distance", PROPERTY_HINT_RANGE,"0.01,1024,0,01") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "clip") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "autoturn") ); + p_list->push_back( PropertyInfo( Variant::REAL, "autoturn_tolerance", PROPERTY_HINT_RANGE,"1,90,0.01") ); + p_list->push_back( PropertyInfo( Variant::REAL, "autoturn_speed", PROPERTY_HINT_RANGE,"1,90,0.01") ); + + +} + +void CharacterCamera::_compute_camera() { + + + // update the transform with the next proposed transform (camera is 1 logic frame delayed) + + /* + float time = get_root_node()->get_frame_time(); + Vector3 oldp = accepted.get_origin(); + Vector3 newp = proposed.get_origin(); + + float frame_dist = time * + if (oldp.distance_to(newp) > + */ + + float time = get_root_node()->get_frame_time(); + + if (true) { + + if (clip_ray[0].clipped && clip_ray[1].clipped && clip_ray[2].clipped) { + //all have been clipped + proposed.origin=clip_ray[1].clip_pos; + + + } else { + + Vector3 rel=proposed.origin-target_pos; + + if (clip_ray[0].clipped && !clip_ray[2].clipped) { + + float distance = target_pos.distance_to(clip_ray[0].clip_pos); + real_t amount = 1.0-(distance/clip_len); + amount = CLAMP(amount,0,1); + + + rel=Matrix3(Vector3(0,1,0)), + rotate_orbit(Vector2(0,autoturn_speed*time*amount)); + } + if (clip_ray[2].clipped && !clip_ray[0].clipped) { + + float distance = target_pos.distance_to(clip_ray[2].clip_pos); + real_t amount = 1.0-(distance/clip_len); + amount = CLAMP(amount,0,1); + + rotate_orbit(Vector2(0,-autoturn_speed*time*amount)); + } + + } + } + + + Transform final; + + static float pos_ratio = 0.9; + static float rot_ratio = 10; + + Vector3 vec1 = accepted.origin; + Vector3 vec2 = proposed.origin; + final.origin = vec2.linear_interpolate(vec1, pos_ratio * time);; + + Quat q1 = accepted.basis; + Quat q2 = proposed.basis; + final.basis = q1.slerp(q2, rot_ratio * time); + + accepted=final; + + _update_camera(); + + // calculate the next proposed transform + + + Vector3 new_pos; + Vector3 character_pos = get_global_transform().origin; + character_pos.y+=height; // height compensate + + if(type==CAMERA_FOLLOW) { + + + + /* calculate some variables */ + + Vector3 rel = follow_pos - character_pos; + + float l = rel.length(); + Vector3 rel_n = (l > 0) ? (rel/l) : Vector3(); +#if 1 + float ang = Math::acos(rel_n.dot( Vector3(0,1,0) )); + + Vector3 tangent = rel_n; + tangent.y=0; // get rid of y + if (tangent.length_squared() < CMP_EPSILON2) + tangent=Vector3(0,0,1); // use Z as tangent if rel is parallel to y + else + tangent.normalize(); + + /* now start applying the rules */ + + //clip distance + if (l > max_distance) + l=max_distance; + if (l < min_distance) + l=min_distance; + + //fix angle + + float ang_min = Math_PI * 0.5 + Math::deg2rad(min_orbit_x); + float ang_max = Math_PI * 0.5 + Math::deg2rad(max_orbit_x); + + if (ang<ang_min) + ang=ang_min; + if (ang>ang_max) + ang=ang_max; + + /* finally, rebuild the validated camera position */ + + new_pos=Vector3(0,Math::cos(ang),0); + new_pos+=tangent*Math::sin(ang); + new_pos*=l; + new_pos+=character_pos; +#else + if (l > max_distance) + l=max_distance; + if (l < min_distance) + l=min_distance; + + new_pos = character_pos + rel_n * l; + + +#endif + follow_pos=new_pos; + + } else if (type==CAMERA_FIXED) { + + + if (distance<min_distance) + distance=min_distance; + if (distance>max_distance) + distance=max_distance; + + if (orbit.x<min_orbit_x) + orbit.x=min_orbit_x; + if (orbit.x>max_orbit_x) + orbit.x=max_orbit_x; + + Matrix3 m; + m.rotate(Vector3(0,1,0),Math::deg2rad(orbit.y)); + m.rotate(Vector3(1,0,0),Math::deg2rad(orbit.x)); + + new_pos = (m.get_axis(2) * distance) + character_pos; + + if (use_lookat_target) { + + Transform t = get_global_transform(); + Vector3 y = t.basis.get_axis(1).normalized(); + Vector3 z = lookat_target - character_pos; + z= (z - y * y.dot(z)).normalized(); + orbit.y = -Math::rad2deg(Math::atan2(z.x,z.z)) + 180; + + /* + Transform t = get_global_transform(); + Vector3 y = t.basis.get_axis(1).normalized(); + Vector3 z = lookat_target - t.origin; + z= (z - y * y.dot(z)).normalized(); + Vector3 x = z.cross(y).normalized(); + Transform t2; + t2.basis.set_axis(0,x); + t2.basis.set_axis(1,y); + t2.basis.set_axis(2,z); + t2.origin=t.origin; + + Vector3 local = t2.xform_inv(camera_pos); + + float ang = Math::atan2(local.x,local.y); + */ + + /* + + Vector3 vec1 = lookat_target - new_pos; + vec1.normalize(); + Vector3 vec2 = character_pos - new_pos; + vec2.normalize(); + + float dot = vec1.dot(vec2); + printf("dot %f\n", dot); + if ( dot < 0.5) { + + rotate_orbit(Vector2(0, 90)); + }; + */ + + + }; + } + + Vector3 target; + if (use_lookat_target) { + + target = lookat_target; + } else { + target = character_pos; + }; + + proposed.set_look_at(new_pos,target,Vector3(0,1,0)); + proposed = proposed * Transform(Matrix3(Vector3(1,0,0),Math::deg2rad(inclination)),Vector3()); //inclination + + + Vector<RID> exclude; + exclude.push_back(target_body); + + + + Vector3 rel = new_pos-target; + + for(int i=0;i<3;i++) { + + PhysicsServer::get_singleton()->query_intersection(clip_ray[i].query,get_world().get_space(),exclude); + PhysicsServer::get_singleton()->query_intersection_segment(clip_ray[i].query,target,target+Matrix3(Vector3(0,1,0),Math::deg2rad(autoturn_tolerance*(i-1.0))).xform(rel)); + clip_ray[i].clipped=false; + clip_ray[i].clip_pos=Vector3(); + } + target_pos=target; + clip_len=rel.length(); + + + +} + +void CharacterCamera::set_use_lookat_target(bool p_use, const Vector3 &p_lookat) { + + use_lookat_target = p_use; + lookat_target = p_lookat; +}; + + +void CharacterCamera::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_PROCESS: { + + + _compute_camera(); + } break; + + case NOTIFICATION_ENTER_SCENE: { + + if (type==CAMERA_FOLLOW) { + + set_orbit(orbit); + set_distance(distance); + } + + accepted=get_global_transform(); + proposed=accepted; + + target_body = RID(); + + Node* parent = get_parent(); + while (parent) { + PhysicsBody* p = parent->cast_to<PhysicsBody>(); + if (p) { + target_body = p->get_body(); + break; + }; + parent = parent->get_parent(); + }; + + } break; + + case NOTIFICATION_TRANSFORM_CHANGED: { + + } break; + case NOTIFICATION_EXIT_SCENE: { + + if (type==CAMERA_FOLLOW) { + distance=get_distance(); + orbit=get_orbit(); + + } + } break; + + case NOTIFICATION_BECAME_CURRENT: { + + set_process(true); + } break; + case NOTIFICATION_LOST_CURRENT: { + + set_process(false); + } break; + } + +} + + +void CharacterCamera::set_camera_type(CameraType p_camera_type) { + + + if (p_camera_type==type) + return; + + type=p_camera_type; + + // do conversions +} + +CharacterCamera::CameraType CharacterCamera::get_camera_type() const { + + return type; + +} + +void CharacterCamera::set_orbit(const Vector2& p_orbit) { + + orbit=p_orbit; + + if(type == CAMERA_FOLLOW && is_inside_scene()) { + + Vector3 char_pos = get_global_transform().origin; + char_pos.y+=height; + float d = char_pos.distance_to(follow_pos); + + Matrix3 m; + m.rotate(Vector3(0,1,0),orbit.y); + m.rotate(Vector3(1,0,0),orbit.x); + + follow_pos=char_pos + m.get_axis(2) * d; + + } + +} +void CharacterCamera::set_orbit_x(float p_x) { + + orbit.x=p_x; + if(type == CAMERA_FOLLOW && is_inside_scene()) + set_orbit(Vector2( p_x, get_orbit().y )); +} +void CharacterCamera::set_orbit_y(float p_y) { + + + orbit.y=p_y; + if(type == CAMERA_FOLLOW && is_inside_scene()) + set_orbit(Vector2( get_orbit().x, p_y )); + +} +Vector2 CharacterCamera::get_orbit() const { + + + if (type == CAMERA_FOLLOW && is_inside_scene()) { + + Vector3 char_pos = get_global_transform().origin; + char_pos.y+=height; + Vector3 rel = (follow_pos - char_pos).normalized(); + Vector2 ret_orbit; + ret_orbit.x = Math::acos( Vector3(0,1,0).dot( rel ) ) - Math_PI * 0.5; + ret_orbit.y = Math::atan2(rel.x,rel.z); + return ret_orbit; + } + return orbit; +} + +void CharacterCamera::rotate_orbit(const Vector2& p_relative) { + + if (type == CAMERA_FOLLOW && is_inside_scene()) { + + Matrix3 m; + m.rotate(Vector3(0,1,0),Math::deg2rad(p_relative.y)); + m.rotate(Vector3(1,0,0),Math::deg2rad(p_relative.x)); + + Vector3 char_pos = get_global_transform().origin; + char_pos.y+=height; + Vector3 rel = (follow_pos - char_pos); + rel = m.xform(rel); + follow_pos=char_pos+rel; + + } + + orbit+=p_relative; +} + +void CharacterCamera::set_height(float p_height) { + + + height=p_height; +} + +float CharacterCamera::get_height() const { + + return height; + +} + +void CharacterCamera::set_max_orbit_x(float p_max) { + + max_orbit_x=p_max; +} + +float CharacterCamera::get_max_orbit_x() const { + + return max_orbit_x; +} + +void CharacterCamera::set_min_orbit_x(float p_min) { + + min_orbit_x=p_min; +} + +float CharacterCamera::get_min_orbit_x() const { + + return min_orbit_x; +} + +float CharacterCamera::get_min_distance() const { + + return min_distance; +} +float CharacterCamera::get_max_distance() const { + + return max_distance; +} + +void CharacterCamera::set_min_distance(float p_min) { + + min_distance=p_min; +} + +void CharacterCamera::set_max_distance(float p_max) { + + max_distance = p_max; +} + + +void CharacterCamera::set_distance(float p_distance) { + + if (type == CAMERA_FOLLOW && is_inside_scene()) { + + Vector3 char_pos = get_global_transform().origin; + char_pos.y+=height; + Vector3 rel = (follow_pos - char_pos).normalized(); + rel*=p_distance; + follow_pos=char_pos+rel; + + } + + distance=p_distance; +} + +float CharacterCamera::get_distance() const { + + if (type == CAMERA_FOLLOW && is_inside_scene()) { + + Vector3 char_pos = get_global_transform().origin; + char_pos.y+=height; + return (follow_pos - char_pos).length(); + + } + + return distance; +} + +void CharacterCamera::set_clip(bool p_enabled) { + + + clip=p_enabled; +} + +bool CharacterCamera::has_clip() const { + + return clip; + +} + + +void CharacterCamera::set_autoturn(bool p_enabled) { + + + autoturn=p_enabled; +} + +bool CharacterCamera::has_autoturn() const { + + return autoturn; + +} + +void CharacterCamera::set_autoturn_tolerance(float p_degrees) { + + + autoturn_tolerance=p_degrees; +} +float CharacterCamera::get_autoturn_tolerance() const { + + + return autoturn_tolerance; +} + +void CharacterCamera::set_inclination(float p_degrees) { + + + inclination=p_degrees; +} +float CharacterCamera::get_inclination() const { + + + return inclination; +} + + +void CharacterCamera::set_autoturn_speed(float p_speed) { + + + autoturn_speed=p_speed; +} +float CharacterCamera::get_autoturn_speed() const { + + return autoturn_speed; + +} + + + + + +void CharacterCamera::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_camera_type","type"),&CharacterCamera::set_camera_type); + ObjectTypeDB::bind_method(_MD("get_camera_type"),&CharacterCamera::get_camera_type); + ObjectTypeDB::bind_method(_MD("set_orbit","orbit"),&CharacterCamera::set_orbit); + ObjectTypeDB::bind_method(_MD("get_orbit"),&CharacterCamera::get_orbit); + ObjectTypeDB::bind_method(_MD("set_orbit_x","x"),&CharacterCamera::set_orbit_x); + ObjectTypeDB::bind_method(_MD("set_orbit_y","y"),&CharacterCamera::set_orbit_y); + ObjectTypeDB::bind_method(_MD("set_min_orbit_x","x"),&CharacterCamera::set_min_orbit_x); + ObjectTypeDB::bind_method(_MD("get_min_orbit_x"),&CharacterCamera::get_min_orbit_x); + ObjectTypeDB::bind_method(_MD("set_max_orbit_x","x"),&CharacterCamera::set_max_orbit_x); + ObjectTypeDB::bind_method(_MD("get_max_orbit_x"),&CharacterCamera::get_max_orbit_x); + ObjectTypeDB::bind_method(_MD("rotate_orbit"),&CharacterCamera::rotate_orbit); + ObjectTypeDB::bind_method(_MD("set_distance","distance"),&CharacterCamera::set_distance); + ObjectTypeDB::bind_method(_MD("get_distance"),&CharacterCamera::get_distance); + ObjectTypeDB::bind_method(_MD("set_clip","enable"),&CharacterCamera::set_clip); + ObjectTypeDB::bind_method(_MD("has_clip"),&CharacterCamera::has_clip); + ObjectTypeDB::bind_method(_MD("set_autoturn","enable"),&CharacterCamera::set_autoturn); + ObjectTypeDB::bind_method(_MD("has_autoturn"),&CharacterCamera::has_autoturn); + ObjectTypeDB::bind_method(_MD("set_autoturn_tolerance","degrees"),&CharacterCamera::set_autoturn_tolerance); + ObjectTypeDB::bind_method(_MD("get_autoturn_tolerance"),&CharacterCamera::get_autoturn_tolerance); + ObjectTypeDB::bind_method(_MD("set_autoturn_speed","speed"),&CharacterCamera::set_autoturn_speed); + ObjectTypeDB::bind_method(_MD("get_autoturn_speed"),&CharacterCamera::get_autoturn_speed); + ObjectTypeDB::bind_method(_MD("set_use_lookat_target","use","lookat"),&CharacterCamera::set_use_lookat_target, DEFVAL(Vector3())); + + ObjectTypeDB::bind_method(_MD("_ray_collision"),&CharacterCamera::_ray_collision); + + BIND_CONSTANT( CAMERA_FIXED ); + BIND_CONSTANT( CAMERA_FOLLOW ); +} + +void CharacterCamera::_ray_collision(Vector3 p_point, Vector3 p_normal, int p_subindex, ObjectID p_against,int p_idx) { + + + clip_ray[p_idx].clip_pos=p_point; + clip_ray[p_idx].clipped=true; +}; + +Transform CharacterCamera::get_camera_transform() const { + + return accepted; +} + + +CharacterCamera::CharacterCamera() { + + + type=CAMERA_FOLLOW; + height=1; + + orbit=Vector2(0,0); + + distance=3; + min_distance=2; + max_distance=5; + + autoturn=false; + autoturn_tolerance=15; + autoturn_speed=20; + + min_orbit_x=-50; + max_orbit_x=70; + inclination=0; + + clip=false; + use_lookat_target = false; + + for(int i=0;i<3;i++) { + clip_ray[i].query=PhysicsServer::get_singleton()->query_create(this, "_ray_collision", i, true); + clip_ray[i].clipped=false; + } + + +} + +CharacterCamera::~CharacterCamera() { + + for(int i=0;i<3;i++) { + PhysicsServer::get_singleton()->free(clip_ray[i].query); + } + + +} +#endif diff --git a/scene/3d/character_camera.h b/scene/3d/character_camera.h new file mode 100644 index 0000000000..f3bdef54a6 --- /dev/null +++ b/scene/3d/character_camera.h @@ -0,0 +1,167 @@ +/*************************************************************************/ +/* character_camera.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef CHARACTER_CAMERA_H +#define CHARACTER_CAMERA_H + + +#include "scene/3d/camera.h" +#if 0 +class CharacterCamera : public Camera { + + OBJ_TYPE( CharacterCamera, Camera ); +public: + + enum CameraType { + CAMERA_FIXED, + CAMERA_FOLLOW + }; + +private: + + + CameraType type; + + //used for follow + Vector3 follow_pos; + //used for fixed + Vector2 orbit; + float distance; + + float height; + + float min_distance; + float max_distance; + + float max_orbit_x; + float min_orbit_x; + + float inclination; + + bool clip; + bool autoturn; + float autoturn_tolerance; + float autoturn_speed; + + + + struct ClipRay { + RID query; + bool clipped; + Vector3 clip_pos; + }; + + ClipRay clip_ray[3]; + Vector3 target_pos; + float clip_len; + + + Transform accepted; + Vector3 proposed_pos; + + bool use_lookat_target; + Vector3 lookat_target; + + void _compute_camera(); + + RID ray_query; + RID left_turn_query; + RID right_turn_query; + RID target_body; + +protected: + + virtual void _request_camera_update() {} //ignore + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + void _notification(int p_what); + + static void _bind_methods(); + + void _ray_collision(Vector3 p_point, Vector3 p_normal, int p_subindex, ObjectID p_against,int p_idx); + +public: + + + void set_camera_type(CameraType p_camera_type); + CameraType get_camera_type() const; + + void set_orbit(const Vector2& p_orbit); + void set_orbit_x(float p_x); + void set_orbit_y(float p_y); + Vector2 get_orbit() const; + + void set_height(float p_height); + float get_height() const; + + void set_inclination(float p_degrees); + float get_inclination() const; + + void set_max_orbit_x(float p_max); + float get_max_orbit_x() const; + + void set_min_orbit_x(float p_min); + float get_min_orbit_x() const; + + void rotate_orbit(const Vector2& p_relative); + + void set_distance(float p_distance); + float get_distance() const; + + float get_min_distance() const; + float get_max_distance() const; + void set_min_distance(float p_min); + void set_max_distance(float p_max); + + + void set_clip(bool p_enabled); + bool has_clip() const; + + void set_autoturn(bool p_enabled); + bool has_autoturn() const; + + void set_autoturn_tolerance(float p_degrees); + float get_autoturn_tolerance() const; + + void set_autoturn_speed(float p_speed); + float get_autoturn_speed() const; + + void set_use_lookat_target(bool p_use, const Vector3 &p_lookat = Vector3()); + + virtual Transform get_camera_transform() const; + + CharacterCamera(); + ~CharacterCamera(); +}; + +VARIANT_ENUM_CAST( CharacterCamera::CameraType ); + +#endif +#endif // CHARACTER_CAMERA_H diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp new file mode 100644 index 0000000000..7ad10d3222 --- /dev/null +++ b/scene/3d/collision_object.cpp @@ -0,0 +1,284 @@ +/*************************************************************************/ +/* collision_object.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "collision_object.h" +#include "servers/physics_server.h" + +void CollisionObject::_update_shapes_from_children() { + + shapes.resize(0); + for(int i=0;i<get_child_count();i++) { + + Node* n = get_child(i); + n->call("_add_to_collision_object",this); + } + +// _update_shapes(); +} + +void CollisionObject::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_WORLD: { + + RID space = get_world()->get_space(); + if (area) { + PhysicsServer::get_singleton()->area_set_space(rid,space); + } else + PhysicsServer::get_singleton()->body_set_space(rid,space); + + //get space + } + + case NOTIFICATION_TRANSFORM_CHANGED: { + + if (area) + PhysicsServer::get_singleton()->area_set_transform(rid,get_global_transform()); + else + PhysicsServer::get_singleton()->body_set_state(rid,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform()); + + } break; + case NOTIFICATION_EXIT_WORLD: { + + if (area) { + PhysicsServer::get_singleton()->area_set_space(rid,RID()); + } else + PhysicsServer::get_singleton()->body_set_space(rid,RID()); + + } break; + } +} + +void CollisionObject::_update_shapes() { + + if (!rid.is_valid()) + return; + + if (area) + PhysicsServer::get_singleton()->area_clear_shapes(rid); + else + PhysicsServer::get_singleton()->body_clear_shapes(rid); + + for(int i=0;i<shapes.size();i++) { + + if (shapes[i].shape.is_null()) + continue; + if (area) + PhysicsServer::get_singleton()->area_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform); + else { + PhysicsServer::get_singleton()->body_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform); + if (shapes[i].trigger) + PhysicsServer::get_singleton()->body_set_shape_as_trigger(rid,i,shapes[i].trigger); + } + } +} + + +bool CollisionObject::_set(const StringName& p_name, const Variant& p_value) { + String name=p_name; + + if (name=="shape_count") { + + shapes.resize(p_value); + _update_shapes(); + _change_notify(); + + } else if (name.begins_with("shapes/")) { + + int idx=name.get_slice("/",1).to_int(); + String what=name.get_slice("/",2); + if (what=="shape") + set_shape(idx,RefPtr(p_value)); + else if (what=="transform") + set_shape_transform(idx,p_value); + else if (what=="trigger") + set_shape_as_trigger(idx,p_value); + + + } else + return false; + + return true; + + +} + +bool CollisionObject::_get(const StringName& p_name,Variant &r_ret) const { + + String name=p_name; + + if (name=="shape_count") { + r_ret= shapes.size(); + } else if (name.begins_with("shapes/")) { + + int idx=name.get_slice("/",1).to_int(); + String what=name.get_slice("/",2); + if (what=="shape") + r_ret= get_shape(idx); + else if (what=="transform") + r_ret= get_shape_transform(idx); + else if (what=="trigger") + r_ret= is_shape_set_as_trigger(idx); + + } else + return false; + + return true; +} + +void CollisionObject::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR) ); + + for(int i=0;i<shapes.size();i++) { + String path="shapes/"+itos(i)+"/"; + p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape",PROPERTY_USAGE_NOEDITOR) ); + p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) ); + p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) ); + + } +} + +void CollisionObject::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("add_shape","shape:Shape","transform"),&CollisionObject::add_shape,DEFVAL(Transform())); + ObjectTypeDB::bind_method(_MD("get_shape_count"),&CollisionObject::get_shape_count); + ObjectTypeDB::bind_method(_MD("set_shape","shape_idx","shape:Shape"),&CollisionObject::set_shape); + ObjectTypeDB::bind_method(_MD("set_shape_transform","shape_idx","transform"),&CollisionObject::set_shape_transform); +// ObjectTypeDB::bind_method(_MD("set_shape_transform","shape_idx","transform"),&CollisionObject::set_shape_transform); + ObjectTypeDB::bind_method(_MD("set_shape_as_trigger","shape_idx","enable"),&CollisionObject::set_shape_as_trigger); + ObjectTypeDB::bind_method(_MD("is_shape_set_as_trigger","shape_idx"),&CollisionObject::is_shape_set_as_trigger); + ObjectTypeDB::bind_method(_MD("get_shape:Shape","shape_idx"),&CollisionObject::get_shape); + ObjectTypeDB::bind_method(_MD("get_shape_transform","shape_idx"),&CollisionObject::get_shape_transform); + ObjectTypeDB::bind_method(_MD("remove_shape","shape_idx"),&CollisionObject::remove_shape); + ObjectTypeDB::bind_method(_MD("clear_shapes"),&CollisionObject::clear_shapes); + ObjectTypeDB::bind_method(_MD("get_rid"),&CollisionObject::get_rid); + +} + + +void CollisionObject::add_shape(const Ref<Shape>& p_shape, const Transform& p_transform) { + + ShapeData sdata; + sdata.shape=p_shape; + sdata.xform=p_transform; + shapes.push_back(sdata); + _update_shapes(); + +} +int CollisionObject::get_shape_count() const { + + return shapes.size(); + +} +void CollisionObject::set_shape(int p_shape_idx, const Ref<Shape>& p_shape) { + + ERR_FAIL_INDEX(p_shape_idx,shapes.size()); + shapes[p_shape_idx].shape=p_shape; + _update_shapes(); +} + +void CollisionObject::set_shape_transform(int p_shape_idx, const Transform& p_transform) { + + ERR_FAIL_INDEX(p_shape_idx,shapes.size()); + shapes[p_shape_idx].xform=p_transform; + + _update_shapes(); +} + +Ref<Shape> CollisionObject::get_shape(int p_shape_idx) const { + + ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),Ref<Shape>()); + return shapes[p_shape_idx].shape; + +} +Transform CollisionObject::get_shape_transform(int p_shape_idx) const { + + ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),Transform()); + return shapes[p_shape_idx].xform; + +} +void CollisionObject::remove_shape(int p_shape_idx) { + + ERR_FAIL_INDEX(p_shape_idx,shapes.size()); + shapes.remove(p_shape_idx); + + _update_shapes(); +} + +void CollisionObject::clear_shapes() { + + shapes.clear(); + + _update_shapes(); +} + +void CollisionObject::set_shape_as_trigger(int p_shape_idx, bool p_trigger) { + + ERR_FAIL_INDEX(p_shape_idx,shapes.size()); + shapes[p_shape_idx].trigger=p_trigger; + if (!area && rid.is_valid()) { + + PhysicsServer::get_singleton()->body_set_shape_as_trigger(rid,p_shape_idx,p_trigger); + + } +} + +bool CollisionObject::is_shape_set_as_trigger(int p_shape_idx) const { + + ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),false); + return shapes[p_shape_idx].trigger; +} + +CollisionObject::CollisionObject(RID p_rid, bool p_area) { + + rid=p_rid; + area=p_area; + if (p_area) { + PhysicsServer::get_singleton()->area_attach_object_instance_ID(rid,get_instance_ID()); + } else { + PhysicsServer::get_singleton()->body_attach_object_instance_ID(rid,get_instance_ID()); + } +// set_transform_notify(true); + +} + + +CollisionObject::CollisionObject() { + + + //owner= + + //set_transform_notify(true); +} + +CollisionObject::~CollisionObject() { + + PhysicsServer::get_singleton()->free(rid); +} diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h new file mode 100644 index 0000000000..54dc6508ab --- /dev/null +++ b/scene/3d/collision_object.h @@ -0,0 +1,90 @@ +/*************************************************************************/ +/* collision_object.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef COLLISION_OBJECT_H +#define COLLISION_OBJECT_H + +#include "scene/3d/spatial.h" +#include "scene/resources/shape.h" + +class CollisionObject : public Spatial { + + OBJ_TYPE( CollisionObject, Spatial ); + + bool area; + RID rid; + + struct ShapeData { + Transform xform; + Ref<Shape> shape; + bool trigger; + + ShapeData() { + trigger=false; + } + + }; + + + Vector<ShapeData> shapes; + + void _update_shapes(); + +friend class CollisionShape; +friend class CollisionPolygon; + void _update_shapes_from_children(); +protected: + + CollisionObject(RID p_rid, bool p_area); + + void _notification(int p_what); + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + static void _bind_methods(); +public: + + + void add_shape(const Ref<Shape>& p_shape, const Transform& p_transform=Transform()); + int get_shape_count() const; + void set_shape(int p_shape_idx, const Ref<Shape>& p_shape); + void set_shape_transform(int p_shape_idx, const Transform& p_transform); + Ref<Shape> get_shape(int p_shape_idx) const; + Transform get_shape_transform(int p_shape_idx) const; + void remove_shape(int p_shape_idx); + void clear_shapes(); + void set_shape_as_trigger(int p_shape_idx, bool p_trigger); + bool is_shape_set_as_trigger(int p_shape_idx) const; + + _FORCE_INLINE_ RID get_rid() const { return rid; } + + CollisionObject(); + ~CollisionObject(); +}; + +#endif // COLLISION_OBJECT__H diff --git a/scene/3d/editable_shape.cpp b/scene/3d/editable_shape.cpp new file mode 100644 index 0000000000..ab3f832028 --- /dev/null +++ b/scene/3d/editable_shape.cpp @@ -0,0 +1,85 @@ +/*************************************************************************/ +/* editable_shape.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "editable_shape.h" + + +void EditableShape::_notification(int p_what) { + + + +} + + +void EditableShape::set_bsp_tree(const BSP_Tree& p_bsp) { + + bsp=p_bsp; +} + +void EditableShape::set_shape(const Ref<Shape>& p_shape) { + + shape=p_shape; +} + + + +EditableShape::EditableShape() +{ +} + + + +///////////////////////// + + +void EditableSphere::set_radius(float p_radius) { + + radius=p_radius; + update_gizmo(); + _change_notify("params/radius"); +} + + +float EditableSphere::get_radius() const{ + + return radius; +} + + +void EditableSphere::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_radius","radius"),&EditableSphere::set_radius); + ObjectTypeDB::bind_method(_MD("get_radius"),&EditableSphere::get_radius); + + ADD_PROPERTY( PropertyInfo(Variant::REAL,"params/radius",PROPERTY_HINT_EXP_RANGE,"0.001,16384,0.001"),_SCS("set_radius"),_SCS("get_radius")); +} + +EditableSphere::EditableSphere() { + + radius=1.0; +} diff --git a/scene/3d/editable_shape.h b/scene/3d/editable_shape.h new file mode 100644 index 0000000000..9accea575c --- /dev/null +++ b/scene/3d/editable_shape.h @@ -0,0 +1,73 @@ +/*************************************************************************/ +/* editable_shape.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef EDITABLE_SHAPE_H +#define EDITABLE_SHAPE_H + +#include "scene/3d/spatial.h" +#include "scene/resources/shape.h" + +class EditableShape : public Spatial { + + OBJ_TYPE(EditableShape,Spatial); + + //can hold either of those + BSP_Tree bsp; + Ref<Shape> shape; + + void _update_parent(); +protected: + + void _notification(int p_what); + + void set_bsp_tree(const BSP_Tree& p_bsp); + void set_shape(const Ref<Shape>& p_shape); +public: + EditableShape(); +}; + + +class EditableSphere : public EditableShape { + + OBJ_TYPE( EditableSphere, EditableShape ); + + + float radius; +protected: + + static void _bind_methods(); +public: + + void set_radius(float p_radius); + float get_radius() const; + + EditableSphere(); +}; + + +#endif // EDITABLE_SHAPE_H diff --git a/scene/3d/follow_camera.cpp b/scene/3d/follow_camera.cpp new file mode 100644 index 0000000000..20a1654b92 --- /dev/null +++ b/scene/3d/follow_camera.cpp @@ -0,0 +1,778 @@ +/*************************************************************************/ +/* follow_camera.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "follow_camera.h" + + +#include "physics_body.h" +#include "scene/resources/surface_tool.h" + +void FollowCamera::_set_initial_orbit(const Vector2& p_orbit) { + + initial_orbit=p_orbit; + set_orbit(p_orbit); +} + + + +void FollowCamera::_clear_queries() { + + if (!queries_active) + return; +#if 0 + for(int i=0;i<3;i++) + PhysicsServer::get_singleton()->query_clear(clip_ray[i].query); +#endif + queries_active=false; + +} + +void FollowCamera::_compute_camera() { + + // update the transform with the next proposed transform (camera is 1 logic frame delayed) + + /* + float time = get_root_node()->get_frame_time(); + Vector3 oldp = accepted.get_origin(); + Vector3 newp = proposed.get_origin(); + + float frame_dist = time * + if (oldp.distance_to(newp) > + */ + + float time = get_process_delta_time(); + bool noblend=false; + + if (clip) { + + if ((clip_ray[0].clipped==clip_ray[2].clipped || fullclip) && clip_ray[1].clipped) { + //all have been clipped + proposed_pos=clip_ray[1].clip_pos-extraclip*(proposed_pos-target_pos).normalized(); + if (clip_ray[0].clipped) + fullclip=true; + noblend=true; + + + } else { + + + //Vector3 rel=follow_pos-target_pos; + + if (clip_ray[0].clipped && !clip_ray[2].clipped) { + + float distance = target_pos.distance_to(clip_ray[0].clip_pos); + real_t amount = 1.0-(distance/clip_len); + amount = CLAMP(amount,0,1)*autoturn_speed*time; + if (clip_ray[1].clipped) + amount*=2.0; + //rotate_rel=Matrix3(Vector3(0,1,0),amount).xform(rel); + rotate_orbit(Vector2(0,amount)); + + } else if (clip_ray[2].clipped && !clip_ray[0].clipped) { + + float distance = target_pos.distance_to(clip_ray[2].clip_pos); + real_t amount = 1.0-(distance/clip_len); + amount = CLAMP(amount,0,1)*autoturn_speed*time; + if (clip_ray[1].clipped) + amount*=2.0; + rotate_orbit(Vector2(0,-amount)); + } + + fullclip=false; + + } + } + + + Vector3 base_pos = get_global_transform().origin; + Vector3 pull_from = base_pos; + pull_from.y+=height; // height compensate + + + + Vector3 camera_target; + if (use_lookat_target) { + + camera_target = lookat_target; + } else { + camera_target = base_pos; + }; + + Transform proposed; + proposed.set_look_at(proposed_pos,camera_target,up_vector); + proposed = proposed * Transform(Matrix3(Vector3(1,0,0),Math::deg2rad(inclination)),Vector3()); //inclination + + + accepted=proposed; + if (smooth && !noblend) { + + + Vector3 vec1 = accepted.origin; + Vector3 vec2 = final.origin; + final.origin = vec2.linear_interpolate(vec1, MIN(1,smooth_pos_ratio * time));; + + Quat q1 = accepted.basis; + Quat q2 = final.basis; + final.basis = q2.slerp(q1, MIN(1,smooth_rot_ratio * time)); + + } else { + final=accepted; + } + + _update_camera(); + + // calculate the next proposed transform + + + Vector3 new_pos; + + { /*follow code*/ + + + + /* calculate some variables */ + + Vector3 rel = follow_pos - pull_from; + + float l = rel.length(); + Vector3 rel_n = (l > 0) ? (rel/l) : Vector3(); + float ang = Math::acos(rel_n.dot( Vector3(0,1,0) )); + + Vector3 tangent = rel_n; + tangent.y=0; // get rid of y + if (tangent.length_squared() < CMP_EPSILON2) + tangent=Vector3(0,0,1); // use Z as tangent if rel is parallel to y + else + tangent.normalize(); + + /* now start applying the rules */ + + //clip distance + if (l > max_distance) + l=max_distance; + if (l < min_distance) + l=min_distance; + + //fix angle + + float ang_min = Math_PI * 0.5 + Math::deg2rad(min_orbit_x); + float ang_max = Math_PI * 0.5 + Math::deg2rad(max_orbit_x); + + if (ang<ang_min) + ang=ang_min; + if (ang>ang_max) + ang=ang_max; + + /* finally, rebuild the validated camera position */ + + new_pos=Vector3(0,Math::cos(ang),0); + new_pos+=tangent*Math::sin(ang); + new_pos*=l; + new_pos+=pull_from; + follow_pos=new_pos; + + } + + proposed_pos=new_pos; + + Vector3 rel = new_pos-camera_target; + + + if (clip) { + + Vector<RID> exclude; + exclude.push_back(target_body); + + for(int i=0;i<3;i++) { + + clip_ray[i].clipped=false; + clip_ray[i].clip_pos=Vector3(); + clip_ray[i].cast_pos=camera_target; + + Vector3 cast_to = camera_target+Matrix3(Vector3(0,1,0),Math::deg2rad(autoturn_tolerance*(i-1.0))).xform(rel); + + + if (i!=1) { + + Vector3 side = rel.cross(Vector3(0,1,0)).normalized()*(i-1.0); + clip_ray[i].cast_pos+side*target_width+rel.normalized()*target_width; + + Vector3 d = -rel; + d.rotate(Vector3(0,1,0),Math::deg2rad(get_fov())*(i-1.0)); + Plane p(new_pos,new_pos+d,new_pos+Vector3(0,1,0)); //fov clipping plane, build a face and use it as plane, facing doesn't matter + Vector3 intersect; + if (p.intersects_segment(clip_ray[i].cast_pos,cast_to,&intersect)) + cast_to=intersect; + + } else { + + cast_to+=rel.normalized()*extraclip; + } + + // PhysicsServer::get_singleton()->query_intersection(clip_ray[i].query,get_world()->get_space(),exclude); + // PhysicsServer::get_singleton()->query_intersection_segment(clip_ray[i].query,clip_ray[i].cast_pos,cast_to); + + + + + } + + queries_active=true; + } else { + + _clear_queries(); + } + target_pos=camera_target; + clip_len=rel.length(); + +} + +void FollowCamera::set_use_lookat_target(bool p_use, const Vector3 &p_lookat) { + + use_lookat_target = p_use; + lookat_target = p_lookat; +}; + + +void FollowCamera::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_PROCESS: { + + + _compute_camera(); + } break; + + case NOTIFICATION_ENTER_WORLD: { + + set_orbit(orbit); + set_distance(distance); + + accepted=final=get_global_transform(); + proposed_pos=accepted.origin; + + target_body = RID(); +/* + Node* parent = get_parent(); + while (parent) { + PhysicsBody* p = parent->cast_to<PhysicsBody>(); + if (p) { + target_body = p->get_body(); + break; + }; + parent = parent->get_parent(); + }; +*/ + set_process(true); + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + } break; + case NOTIFICATION_EXIT_WORLD: { + + distance=get_distance(); + orbit=get_orbit(); + _clear_queries(); + + } break; + case NOTIFICATION_BECAME_CURRENT: { + + set_process(true); + } break; + case NOTIFICATION_LOST_CURRENT: { + + set_process(false); + _clear_queries(); + + } break; + } + +} + + + +void FollowCamera::set_orbit(const Vector2& p_orbit) { + + orbit=p_orbit; + + if(is_inside_scene()) { + + Vector3 char_pos = get_global_transform().origin; + char_pos.y+=height; + float d = char_pos.distance_to(follow_pos); + + Matrix3 m; + m.rotate(Vector3(0,1,0),orbit.y); + m.rotate(Vector3(1,0,0),orbit.x); + + follow_pos=char_pos + m.get_axis(2) * d; + + } + + update_gizmo(); + +} +void FollowCamera::set_orbit_x(float p_x) { + + orbit.x=p_x; + if(is_inside_scene()) + set_orbit(Vector2( p_x, get_orbit().y )); +} +void FollowCamera::set_orbit_y(float p_y) { + + + orbit.y=p_y; + if(is_inside_scene()) + set_orbit(Vector2( get_orbit().x, p_y )); + +} +Vector2 FollowCamera::get_orbit() const { + + + if (is_inside_scene()) { + + Vector3 char_pos = get_global_transform().origin; + char_pos.y+=height; + Vector3 rel = (follow_pos - char_pos).normalized(); + Vector2 ret_orbit; + ret_orbit.x = Math::acos( Vector3(0,1,0).dot( rel ) ) - Math_PI * 0.5; + ret_orbit.y = Math::atan2(rel.x,rel.z); + return ret_orbit; + } + return orbit; +} + +void FollowCamera::rotate_orbit(const Vector2& p_relative) { + + if (is_inside_scene()) { + + Matrix3 m; + m.rotate(Vector3(0,1,0),Math::deg2rad(p_relative.y)); + m.rotate(Vector3(1,0,0),Math::deg2rad(p_relative.x)); + + Vector3 char_pos = get_global_transform().origin; + char_pos.y+=height; + Vector3 rel = (follow_pos - char_pos); + rel = m.xform(rel); + follow_pos=char_pos+rel; + + } + + orbit+=p_relative; + update_gizmo(); +} + +void FollowCamera::set_height(float p_height) { + + + height=p_height; + update_gizmo(); +} + +float FollowCamera::get_height() const { + + return height; + +} + +void FollowCamera::set_max_orbit_x(float p_max) { + + max_orbit_x=p_max; + update_gizmo(); +} + +float FollowCamera::get_max_orbit_x() const { + + return max_orbit_x; +} + +void FollowCamera::set_min_orbit_x(float p_min) { + + min_orbit_x=p_min; + update_gizmo(); +} + +float FollowCamera::get_min_orbit_x() const { + + return min_orbit_x; +} + +float FollowCamera::get_min_distance() const { + + return min_distance; +} +float FollowCamera::get_max_distance() const { + + return max_distance; +} + +void FollowCamera::set_min_distance(float p_min) { + + min_distance=p_min; + update_gizmo(); +} + +void FollowCamera::set_max_distance(float p_max) { + + max_distance = p_max; + update_gizmo(); +} + + +void FollowCamera::set_distance(float p_distance) { + + if (is_inside_scene()) { + + Vector3 char_pos = get_global_transform().origin; + char_pos.y+=height; + Vector3 rel = (follow_pos - char_pos).normalized(); + rel*=p_distance; + follow_pos=char_pos+rel; + + } + + distance=p_distance; +} + +float FollowCamera::get_distance() const { + + if (is_inside_scene()) { + + Vector3 char_pos = get_global_transform().origin; + char_pos.y+=height; + return (follow_pos - char_pos).length(); + + } + + return distance; +} + +void FollowCamera::set_clip(bool p_enabled) { + + + clip=p_enabled; + + if (!p_enabled) + _clear_queries(); +} + +bool FollowCamera::has_clip() const { + + return clip; + +} + + +void FollowCamera::set_autoturn(bool p_enabled) { + + + autoturn=p_enabled; +} + +bool FollowCamera::has_autoturn() const { + + return autoturn; + +} + +void FollowCamera::set_autoturn_tolerance(float p_degrees) { + + + autoturn_tolerance=p_degrees; +} +float FollowCamera::get_autoturn_tolerance() const { + + + return autoturn_tolerance; +} + +void FollowCamera::set_inclination(float p_degrees) { + + + inclination=p_degrees; +} +float FollowCamera::get_inclination() const { + + + return inclination; +} + + +void FollowCamera::set_autoturn_speed(float p_speed) { + + + autoturn_speed=p_speed; +} + +float FollowCamera::get_autoturn_speed() const { + + return autoturn_speed; + +} + + +RES FollowCamera::_get_gizmo_geometry() const { + + Ref<SurfaceTool> surface_tool( memnew( SurfaceTool )); + + Ref<FixedMaterial> mat( memnew( FixedMaterial )); + + mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(1.0,0.5,1.0,0.3) ); + mat->set_line_width(4); + mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); + mat->set_flag(Material::FLAG_UNSHADED,true); + mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true); + + surface_tool->begin(Mesh::PRIMITIVE_LINES); + surface_tool->set_material(mat); + + + int steps=16; + + Vector3 base_up = Matrix3(Vector3(1,0,0),Math::deg2rad(max_orbit_x)).get_axis(2); + Vector3 base_down = Matrix3(Vector3(1,0,0),Math::deg2rad(min_orbit_x)).get_axis(2); + + Vector3 ofs(0,height,0); + + for(int i=0;i<steps;i++) { + + + Matrix3 rot(Vector3(0,1,0),Math_PI*2*float(i)/steps); + Matrix3 rot2(Vector3(0,1,0),Math_PI*2*float(i+1)/steps); + + Vector3 up = rot.xform(base_up); + Vector3 up2 = rot2.xform(base_up); + + Vector3 down = rot.xform(base_down); + Vector3 down2 = rot2.xform(base_down); + + surface_tool->add_vertex(ofs+up*min_distance); + surface_tool->add_vertex(ofs+up*max_distance); + surface_tool->add_vertex(ofs+up*min_distance); + surface_tool->add_vertex(ofs+up2*min_distance); + surface_tool->add_vertex(ofs+up*max_distance); + surface_tool->add_vertex(ofs+up2*max_distance); + + surface_tool->add_vertex(ofs+down*min_distance); + surface_tool->add_vertex(ofs+down*max_distance); + surface_tool->add_vertex(ofs+down*min_distance); + surface_tool->add_vertex(ofs+down2*min_distance); + surface_tool->add_vertex(ofs+down*max_distance); + surface_tool->add_vertex(ofs+down2*max_distance); + + int substeps = 8; + + for(int j=0;j<substeps;j++) { + + Vector3 a = up.linear_interpolate(down,float(j)/substeps).normalized()*max_distance; + Vector3 b = up.linear_interpolate(down,float(j+1)/substeps).normalized()*max_distance; + Vector3 am = up.linear_interpolate(down,float(j)/substeps).normalized()*min_distance; + Vector3 bm = up.linear_interpolate(down,float(j+1)/substeps).normalized()*min_distance; + + surface_tool->add_vertex(ofs+a); + surface_tool->add_vertex(ofs+b); + surface_tool->add_vertex(ofs+am); + surface_tool->add_vertex(ofs+bm); + + } + } + + + return surface_tool->commit(); + + +} + + +void FollowCamera::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_set_initial_orbit","orbit"),&FollowCamera::_set_initial_orbit); + ObjectTypeDB::bind_method(_MD("set_orbit","orbit"),&FollowCamera::set_orbit); + ObjectTypeDB::bind_method(_MD("get_orbit"),&FollowCamera::get_orbit); + ObjectTypeDB::bind_method(_MD("set_orbit_x","x"),&FollowCamera::set_orbit_x); + ObjectTypeDB::bind_method(_MD("set_orbit_y","y"),&FollowCamera::set_orbit_y); + ObjectTypeDB::bind_method(_MD("set_min_orbit_x","x"),&FollowCamera::set_min_orbit_x); + ObjectTypeDB::bind_method(_MD("get_min_orbit_x"),&FollowCamera::get_min_orbit_x); + ObjectTypeDB::bind_method(_MD("set_max_orbit_x","x"),&FollowCamera::set_max_orbit_x); + ObjectTypeDB::bind_method(_MD("get_max_orbit_x"),&FollowCamera::get_max_orbit_x); + ObjectTypeDB::bind_method(_MD("set_height","height"),&FollowCamera::set_height); + ObjectTypeDB::bind_method(_MD("get_height"),&FollowCamera::get_height); + ObjectTypeDB::bind_method(_MD("set_inclination","inclination"),&FollowCamera::set_inclination); + ObjectTypeDB::bind_method(_MD("get_inclination"),&FollowCamera::get_inclination); + + ObjectTypeDB::bind_method(_MD("rotate_orbit"),&FollowCamera::rotate_orbit); + ObjectTypeDB::bind_method(_MD("set_distance","distance"),&FollowCamera::set_distance); + ObjectTypeDB::bind_method(_MD("get_distance"),&FollowCamera::get_distance); + ObjectTypeDB::bind_method(_MD("set_max_distance","max_distance"),&FollowCamera::set_max_distance); + ObjectTypeDB::bind_method(_MD("get_max_distance"),&FollowCamera::get_max_distance); + ObjectTypeDB::bind_method(_MD("set_min_distance","min_distance"),&FollowCamera::set_min_distance); + ObjectTypeDB::bind_method(_MD("get_min_distance"),&FollowCamera::get_min_distance); + ObjectTypeDB::bind_method(_MD("set_clip","enable"),&FollowCamera::set_clip); + ObjectTypeDB::bind_method(_MD("has_clip"),&FollowCamera::has_clip); + ObjectTypeDB::bind_method(_MD("set_autoturn","enable"),&FollowCamera::set_autoturn); + ObjectTypeDB::bind_method(_MD("has_autoturn"),&FollowCamera::has_autoturn); + ObjectTypeDB::bind_method(_MD("set_autoturn_tolerance","degrees"),&FollowCamera::set_autoturn_tolerance); + ObjectTypeDB::bind_method(_MD("get_autoturn_tolerance"),&FollowCamera::get_autoturn_tolerance); + ObjectTypeDB::bind_method(_MD("set_autoturn_speed","speed"),&FollowCamera::set_autoturn_speed); + ObjectTypeDB::bind_method(_MD("get_autoturn_speed"),&FollowCamera::get_autoturn_speed); + ObjectTypeDB::bind_method(_MD("set_smoothing","enable"),&FollowCamera::set_smoothing); + ObjectTypeDB::bind_method(_MD("has_smoothing"),&FollowCamera::has_smoothing); + ObjectTypeDB::bind_method(_MD("set_rotation_smoothing","amount"),&FollowCamera::set_rotation_smoothing); + ObjectTypeDB::bind_method(_MD("get_rotation_smoothing"),&FollowCamera::get_rotation_smoothing); + ObjectTypeDB::bind_method(_MD("set_translation_smoothing","amount"),&FollowCamera::set_translation_smoothing); + ObjectTypeDB::bind_method(_MD("get_translation_smoothing"),&FollowCamera::get_translation_smoothing); + ObjectTypeDB::bind_method(_MD("set_use_lookat_target","use","lookat"),&FollowCamera::set_use_lookat_target, DEFVAL(Vector3())); + ObjectTypeDB::bind_method(_MD("set_up_vector","vector"),&FollowCamera::set_up_vector); + ObjectTypeDB::bind_method(_MD("get_up_vector"),&FollowCamera::get_up_vector); + + ObjectTypeDB::bind_method(_MD("_ray_collision"),&FollowCamera::_ray_collision); + + ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "orbit" ), _SCS("_set_initial_orbit"),_SCS("get_orbit") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "height", PROPERTY_HINT_RANGE,"-1024,1024,0.01" ), _SCS("set_height"), _SCS("get_height") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "inclination", PROPERTY_HINT_RANGE,"-90,90,0.01" ), _SCS("set_inclination"), _SCS("get_inclination") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "max_orbit_x", PROPERTY_HINT_RANGE,"-90,90,0.01" ), _SCS("set_max_orbit_x"), _SCS("get_max_orbit_x") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "min_orbit_x", PROPERTY_HINT_RANGE,"-90,90,0.01" ), _SCS("set_min_orbit_x"), _SCS("get_min_orbit_x") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "min_distance", PROPERTY_HINT_RANGE,"0,100,0.01" ), _SCS("set_min_distance"), _SCS("get_min_distance") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "max_distance", PROPERTY_HINT_RANGE,"0,100,0.01" ), _SCS("set_max_distance"), _SCS("get_max_distance") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "distance", PROPERTY_HINT_RANGE,"0.01,1024,0,01"), _SCS("set_distance"), _SCS("get_distance") ); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "clip"), _SCS("set_clip"), _SCS("has_clip") ); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "autoturn"), _SCS("set_autoturn"), _SCS("has_autoturn") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "autoturn_tolerance", PROPERTY_HINT_RANGE,"1,90,0.01") , _SCS("set_autoturn_tolerance"), _SCS("get_autoturn_tolerance") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "autoturn_speed", PROPERTY_HINT_RANGE,"1,90,0.01"), _SCS("set_autoturn_speed"), _SCS("get_autoturn_speed") ); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "smoothing"), _SCS("set_smoothing"), _SCS("has_smoothing") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "translation_smooth", PROPERTY_HINT_RANGE,"0.01,128,0.01"), _SCS("set_translation_smoothing"), _SCS("get_translation_smoothing") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "rotation_smooth", PROPERTY_HINT_RANGE,"0.01,128,0.01"), _SCS("set_rotation_smoothing"), _SCS("get_rotation_smoothing") ); + + +} + +void FollowCamera::_ray_collision(Vector3 p_point, Vector3 p_normal, int p_subindex, ObjectID p_against,int p_idx) { + + clip_ray[p_idx].clip_pos=p_point; + clip_ray[p_idx].clipped=true; + +}; + +Transform FollowCamera::get_camera_transform() const { + + return final; +} + +void FollowCamera::set_smoothing(bool p_enable) { + + smooth=p_enable; +} + +bool FollowCamera::has_smoothing() const { + + return smooth; +} + +void FollowCamera::set_translation_smoothing(float p_amount) { + + smooth_pos_ratio=p_amount; +} +float FollowCamera::get_translation_smoothing() const { + + return smooth_pos_ratio; +} + +void FollowCamera::set_rotation_smoothing(float p_amount) { + + smooth_rot_ratio=p_amount; + +} + +void FollowCamera::set_up_vector(const Vector3& p_up) { + + up_vector=p_up; +} + +Vector3 FollowCamera::get_up_vector() const{ + + return up_vector; +} + +float FollowCamera::get_rotation_smoothing() const { + + return smooth_pos_ratio; + +} + + +FollowCamera::FollowCamera() { + + + height=1; + + orbit=Vector2(0,0); + up_vector=Vector3(0,1,0); + + distance=3; + min_distance=2; + max_distance=5; + + autoturn=true; + autoturn_tolerance=10; + autoturn_speed=80; + + min_orbit_x=-50; + max_orbit_x=70; + inclination=0; + target_width=0.3; + + clip=true; + use_lookat_target = false; + extraclip=0.3; + fullclip=false; + + smooth=true; + smooth_rot_ratio=10; + smooth_pos_ratio=10; + + + for(int i=0;i<3;i++) { +// clip_ray[i].query=PhysicsServer::get_singleton()->query_create(this, "_ray_collision", i, true); + clip_ray[i].clipped=false; + } + + queries_active=false; + + +} + +FollowCamera::~FollowCamera() { + + for(int i=0;i<3;i++) { + PhysicsServer::get_singleton()->free(clip_ray[i].query); + } + + +} diff --git a/scene/3d/follow_camera.h b/scene/3d/follow_camera.h new file mode 100644 index 0000000000..10912eb606 --- /dev/null +++ b/scene/3d/follow_camera.h @@ -0,0 +1,180 @@ +/*************************************************************************/ +/* follow_camera.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef FOLLOW_CAMERA_H +#define FOLLOW_CAMERA_H + +#include "scene/3d/camera.h" + +class FollowCamera : public Camera { + + OBJ_TYPE( FollowCamera, Camera ); + +private: + + + //used for follow + Vector3 follow_pos; + //used for fixed + Vector2 initial_orbit; + Vector2 orbit; + float distance; + + float height; + float target_width; + + float min_distance; + float max_distance; + + float max_orbit_x; + float min_orbit_x; + + float inclination; + float extraclip; + bool fullclip; + + bool clip; + bool autoturn; + float autoturn_tolerance; + float autoturn_speed; + + bool smooth; + float smooth_rot_ratio; + float smooth_pos_ratio; + + + + struct ClipRay { + RID query; + bool clipped; + Vector3 cast_pos; + Vector3 clip_pos; + }; + + ClipRay clip_ray[3]; + Vector3 target_pos; + float clip_len; + + Vector3 up_vector; + + + virtual RES _get_gizmo_geometry() const; + + Transform ted; + Vector3 proposed_pos; + Transform accepted; + Transform final; + RID target_body; + + bool use_lookat_target; + Vector3 lookat_target; + + void _compute_camera(); + + bool queries_active; + void _clear_queries(); + + void _set_initial_orbit(const Vector2& p_orbit); + +protected: + + virtual void _request_camera_update() {} //ignore + + void _notification(int p_what); + + static void _bind_methods(); + + void _ray_collision(Vector3 p_point, Vector3 p_normal, int p_subindex, ObjectID p_against,int p_idx); + +public: + + + void set_orbit(const Vector2& p_orbit); + void set_orbit_x(float p_x); + void set_orbit_y(float p_y); + Vector2 get_orbit() const; + + void set_height(float p_height); + float get_height() const; + + void set_inclination(float p_degrees); + float get_inclination() const; + + void set_max_orbit_x(float p_max); + float get_max_orbit_x() const; + + void set_min_orbit_x(float p_min); + float get_min_orbit_x() const; + + void rotate_orbit(const Vector2& p_relative); + + void set_distance(float p_distance); + float get_distance() const; + + float get_min_distance() const; + float get_max_distance() const; + void set_min_distance(float p_min); + void set_max_distance(float p_max); + + /** FINISH THIS AND CLEAN IT UP */ + + void set_clip(bool p_enabled); + bool has_clip() const; + + void set_autoturn(bool p_enabled); + bool has_autoturn() const; + + void set_autoturn_tolerance(float p_degrees); + float get_autoturn_tolerance() const; + + void set_autoturn_speed(float p_speed); + float get_autoturn_speed() const; + + void set_smoothing(bool p_enable); + bool has_smoothing() const; + + void set_translation_smoothing(float p_amount); + float get_translation_smoothing() const; + + void set_rotation_smoothing(float p_amount); + float get_rotation_smoothing() const; + + void set_use_lookat_target(bool p_use, const Vector3 &p_lookat = Vector3()); + + void set_up_vector(const Vector3& p_up); + Vector3 get_up_vector() const; + + virtual Transform get_camera_transform() const; + + FollowCamera(); + ~FollowCamera(); +}; + + + +#endif // FOLLOW_CAMERA_H diff --git a/scene/3d/interpolated_camera.cpp b/scene/3d/interpolated_camera.cpp new file mode 100644 index 0000000000..4d8c9cf7a5 --- /dev/null +++ b/scene/3d/interpolated_camera.cpp @@ -0,0 +1,157 @@ +/*************************************************************************/ +/* interpolated_camera.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "interpolated_camera.h" + + +void InterpolatedCamera::_notification(int p_what) { + + switch(p_what) { + case NOTIFICATION_ENTER_SCENE: { + + if (get_scene()->is_editor_hint() && enabled) + set_fixed_process(false); + + } break; + case NOTIFICATION_PROCESS: { + + if (!enabled) + break; + if (has_node(target)) { + + Spatial *node = get_node(target)->cast_to<Spatial>(); + if (!node) + break; + + float delta = speed*get_process_delta_time(); + Transform target_xform = node->get_global_transform(); + Transform local_transform = get_transform(); + local_transform = local_transform.interpolate_with(target_xform,delta); + set_global_transform(local_transform); + + if (node->cast_to<Camera>()) { + Camera *cam = node->cast_to<Camera>(); + if (cam->get_projection()==get_projection()) { + + float new_near = Math::lerp(get_znear(),cam->get_znear(),delta); + float new_far = Math::lerp(get_zfar(),cam->get_zfar(),delta); + + if (cam->get_projection()==PROJECTION_ORTHOGONAL) { + + float size = Math::lerp(get_size(),cam->get_size(),delta); + set_orthogonal(size,new_near,new_far); + } else { + + float fov = Math::lerp(get_fov(),cam->get_fov(),delta); + set_perspective(fov,new_near,new_far); + } + } + } + + + } + + } break; + } +} + +void InterpolatedCamera::_set_target(const Object *p_target) { + + ERR_FAIL_NULL(p_target); + set_target(p_target->cast_to<Spatial>()); +} + +void InterpolatedCamera::set_target(const Spatial *p_target) { + + ERR_FAIL_NULL(p_target); + target=get_path_to(p_target); +} + + +void InterpolatedCamera::set_target_path(const NodePath& p_path){ + + target=p_path; +} + +NodePath InterpolatedCamera::get_target_path() const{ + + return target; +} + +void InterpolatedCamera::set_interpolation_enabled(bool p_enable) { + + if (enabled==p_enable) + return; + enabled=p_enable; + if (p_enable) { + if (is_inside_scene() && get_scene()->is_editor_hint()) + return; + set_process(true); + } else + set_process(false); +} + +bool InterpolatedCamera::is_interpolation_enabled() const { + + return enabled; +} + +void InterpolatedCamera::set_speed(real_t p_speed) { + + speed=p_speed; +} + +real_t InterpolatedCamera::get_speed() const { + + return speed; +} + + +void InterpolatedCamera::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_target_path","target_path"),&InterpolatedCamera::set_target_path); + ObjectTypeDB::bind_method(_MD("get_target_path"),&InterpolatedCamera::get_target_path); + ObjectTypeDB::bind_method(_MD("set_target","target"),&InterpolatedCamera::_set_target); + + ObjectTypeDB::bind_method(_MD("set_speed","speed"),&InterpolatedCamera::set_speed); + ObjectTypeDB::bind_method(_MD("get_speed"),&InterpolatedCamera::get_speed); + + ObjectTypeDB::bind_method(_MD("set_interpolation_enabled","target_path"),&InterpolatedCamera::set_interpolation_enabled); + ObjectTypeDB::bind_method(_MD("is_interpolation_enabled"),&InterpolatedCamera::is_interpolation_enabled); + + ADD_PROPERTY( PropertyInfo(Variant::NODE_PATH,"target"), _SCS("set_target_path"), _SCS("get_target_path") ); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"speed"), _SCS("set_speed"), _SCS("get_speed") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"), _SCS("set_interpolation_enabled"), _SCS("is_interpolation_enabled") ); +} + +InterpolatedCamera::InterpolatedCamera() { + + enabled=false; + speed=1; + +} diff --git a/scene/3d/interpolated_camera.h b/scene/3d/interpolated_camera.h new file mode 100644 index 0000000000..da0e3d562b --- /dev/null +++ b/scene/3d/interpolated_camera.h @@ -0,0 +1,63 @@ +/*************************************************************************/ +/* interpolated_camera.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef INTERPOLATED_CAMERA_H
+#define INTERPOLATED_CAMERA_H
+
+#include "scene/3d/camera.h"
+
+class InterpolatedCamera : public Camera {
+
+ OBJ_TYPE(InterpolatedCamera,Camera);
+
+ bool enabled;
+ real_t speed;
+ NodePath target;
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+ void _set_target(const Object *p_target);
+
+public:
+
+ void set_target(const Spatial *p_target);
+ void set_target_path(const NodePath& p_path);
+ NodePath get_target_path() const;
+
+ void set_speed(real_t p_speed);
+ real_t get_speed() const;
+
+ void set_interpolation_enabled(bool p_enable);
+ bool is_interpolation_enabled() const;
+
+
+ InterpolatedCamera();
+};
+
+#endif // INTERPOLATED_CAMERA_H
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp new file mode 100644 index 0000000000..94c56850ef --- /dev/null +++ b/scene/3d/light.cpp @@ -0,0 +1,585 @@ +/*************************************************************************/ +/* light.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "light.h" + +#include "globals.h" +#include "scene/resources/surface_tool.h" + + +static const char* _light_param_names[VS::LIGHT_PARAM_MAX]={ + "params/spot_attenuation", + "params/spot_angle", + "params/radius", + "params/energy", + "params/attenuation", + "shadow/darkening", + "shadow/z_offset", + "shadow/z_slope_scale" +}; + +void Light::set_parameter(Parameter p_param, float p_value) { + + ERR_FAIL_INDEX(p_param, PARAM_MAX); + vars[p_param]=p_value; + VisualServer::get_singleton()->light_set_param(light,(VisualServer::LightParam)p_param,p_value); + if (p_param==PARAM_RADIUS || p_param==PARAM_SPOT_ANGLE) + update_gizmo(); + _change_notify(_light_param_names[p_param]); +// _change_notify(_param_names[p_param]); +} + +float Light::get_parameter(Parameter p_param) const { + + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); + return vars[p_param]; + +} + +void Light::set_color(LightColor p_color, const Color& p_value) { + + ERR_FAIL_INDEX(p_color, 3); + colors[p_color]=p_value; + VisualServer::get_singleton()->light_set_color(light,(VisualServer::LightColor)p_color,p_value); + //_change_notify(_color_names[p_color]); + +} +Color Light::get_color(LightColor p_color) const { + + ERR_FAIL_INDEX_V(p_color, 3, Color()); + return colors[p_color]; + +} + + +void Light::set_project_shadows(bool p_enabled) { + + shadows=p_enabled; + VisualServer::get_singleton()->light_set_shadow(light, p_enabled); + _change_notify("shadow"); +} +bool Light::has_project_shadows() const { + + return shadows; +} + +void Light::set_projector(const Ref<Texture>& p_projector) { + + projector=p_projector; + VisualServer::get_singleton()->light_set_projector(light, projector.is_null()?RID():projector->get_rid()); +} + +Ref<Texture> Light::get_projector() const { + + return projector; +} + + +bool Light::_can_gizmo_scale() const { + + return false; +} + + +static void _make_sphere(int p_lats, int p_lons, float p_radius, Ref<SurfaceTool> p_tool) { + + + p_tool->begin(Mesh::PRIMITIVE_TRIANGLES); + + for(int i = 1; i <= p_lats; i++) { + double lat0 = Math_PI * (-0.5 + (double) (i - 1) / p_lats); + double z0 = Math::sin(lat0); + double zr0 = Math::cos(lat0); + + double lat1 = Math_PI * (-0.5 + (double) i / p_lats); + double z1 = Math::sin(lat1); + double zr1 = Math::cos(lat1); + + for(int j = p_lons; j >= 1; j--) { + + double lng0 = 2 * Math_PI * (double) (j - 1) / p_lons; + double x0 = Math::cos(lng0); + double y0 = Math::sin(lng0); + + double lng1 = 2 * Math_PI * (double) (j) / p_lons; + double x1 = Math::cos(lng1); + double y1 = Math::sin(lng1); + + + Vector3 v[4]={ + Vector3(x1 * zr0, z0, y1 *zr0), + Vector3(x1 * zr1, z1, y1 *zr1), + Vector3(x0 * zr1, z1, y0 *zr1), + Vector3(x0 * zr0, z0, y0 *zr0) + }; + +#define ADD_POINT(m_idx) \ + p_tool->add_normal(v[m_idx]);\ + p_tool->add_vertex(v[m_idx]*p_radius); + + ADD_POINT(0); + ADD_POINT(1); + ADD_POINT(2); + + ADD_POINT(2); + ADD_POINT(3); + ADD_POINT(0); + } + } + +} + +RES Light::_get_gizmo_geometry() const { + + + Ref<FixedMaterial> mat_area( memnew( FixedMaterial )); + + mat_area->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.7,0.6,0.0,0.05) ); + mat_area->set_parameter( FixedMaterial::PARAM_EMISSION,Color(0.7,0.7,0.7) ); + mat_area->set_blend_mode( Material::BLEND_MODE_ADD ); + mat_area->set_flag(Material::FLAG_DOUBLE_SIDED,true); + mat_area->set_hint(Material::HINT_NO_DEPTH_DRAW,true); + + Ref<FixedMaterial> mat_light( memnew( FixedMaterial )); + + mat_light->set_parameter( FixedMaterial::PARAM_DIFFUSE, Color(1.0,1.0,0.8,0.9) ); + mat_light->set_flag(Material::FLAG_UNSHADED,true); + + Ref< Mesh > mesh; + + Ref<SurfaceTool> surftool( memnew( SurfaceTool )); + + switch(type) { + + case VisualServer::LIGHT_DIRECTIONAL: { + + + mat_area->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.9,0.8,0.1,0.8) ); + mat_area->set_blend_mode( Material::BLEND_MODE_MIX); + mat_area->set_flag(Material::FLAG_DOUBLE_SIDED,false); + mat_area->set_flag(Material::FLAG_UNSHADED,true); + + _make_sphere( 5,5,0.6, surftool ); + surftool->set_material(mat_light); + mesh=surftool->commit(mesh); + + // float radius=1; + + surftool->begin(Mesh::PRIMITIVE_TRIANGLES); + + const int arrow_points=5; + Vector3 arrow[arrow_points]={ + Vector3(0,0,2), + Vector3(1,1,2), + Vector3(1,1,-1), + Vector3(2,2,-1), + Vector3(0,0,-3) + }; + + int arrow_sides=4; + + + for(int i = 0; i < arrow_sides ; i++) { + + + Matrix3 ma(Vector3(0,0,1),Math_PI*2*float(i)/arrow_sides); + Matrix3 mb(Vector3(0,0,1),Math_PI*2*float(i+1)/arrow_sides); + + + for(int j=0;j<arrow_points-1;j++) { + + Vector3 points[4]={ + ma.xform(arrow[j]), + mb.xform(arrow[j]), + mb.xform(arrow[j+1]), + ma.xform(arrow[j+1]), + }; + + Vector3 n = Plane(points[0],points[1],points[2]).normal; + + surftool->add_normal(n); + surftool->add_vertex(points[0]); + surftool->add_normal(n); + surftool->add_vertex(points[1]); + surftool->add_normal(n); + surftool->add_vertex(points[2]); + + surftool->add_normal(n); + surftool->add_vertex(points[0]); + surftool->add_normal(n); + surftool->add_vertex(points[2]); + surftool->add_normal(n); + surftool->add_vertex(points[3]); + + + } + + + } + + surftool->set_material(mat_area); + mesh=surftool->commit(mesh); + + + + } break; + case VisualServer::LIGHT_OMNI: { + + + _make_sphere( 20,20,vars[PARAM_RADIUS], surftool ); + surftool->set_material(mat_area); + mesh=surftool->commit(mesh); + _make_sphere(5,5, 0.1, surftool ); + surftool->set_material(mat_light); + mesh=surftool->commit(mesh); + } break; + + case VisualServer::LIGHT_SPOT: { + + _make_sphere( 5,5,0.1, surftool ); + surftool->set_material(mat_light); + mesh=surftool->commit(mesh); + + // make cone + int points=24; + float len=vars[PARAM_RADIUS]; + float size=Math::tan(Math::deg2rad(vars[PARAM_SPOT_ANGLE]))*len; + + surftool->begin(Mesh::PRIMITIVE_TRIANGLES); + + for(int i = 0; i < points; i++) { + + float x0=Math::sin(i * Math_PI * 2 / points); + float y0=Math::cos(i * Math_PI * 2 / points); + float x1=Math::sin((i+1) * Math_PI * 2 / points); + float y1=Math::cos((i+1) * Math_PI * 2 / points); + + Vector3 v1=Vector3(x0*size,y0*size,-len).normalized()*len; + Vector3 v2=Vector3(x1*size,y1*size,-len).normalized()*len; + + Vector3 v3=Vector3(0,0,0); + Vector3 v4=Vector3(0,0,v1.z); + + Vector3 n = Plane(v1,v2,v3).normal; + + + surftool->add_normal(n); + surftool->add_vertex(v1); + surftool->add_normal(n); + surftool->add_vertex(v2); + surftool->add_normal(n); + surftool->add_vertex(v3); + + n=Vector3(0,0,-1); + + surftool->add_normal(n); + surftool->add_vertex(v1); + surftool->add_normal(n); + surftool->add_vertex(v2); + surftool->add_normal(n); + surftool->add_vertex(v4); + + + } + + surftool->set_material(mat_area); + mesh=surftool->commit(mesh); + + + } break; + } + + return mesh; +} + + +AABB Light::get_aabb() const { + + if (type==VisualServer::LIGHT_DIRECTIONAL) { + + return AABB( Vector3(-1,-1,-1), Vector3(2, 2, 2 ) ); + + } else if (type==VisualServer::LIGHT_OMNI) { + + return AABB( Vector3(-1,-1,-1) * vars[PARAM_RADIUS], Vector3(2, 2, 2 ) * vars[PARAM_RADIUS]); + + } else if (type==VisualServer::LIGHT_SPOT) { + + float len=vars[PARAM_RADIUS]; + float size=Math::tan(Math::deg2rad(vars[PARAM_SPOT_ANGLE]))*len; + return AABB( Vector3( -size,-size,-len ), Vector3( size*2, size*2, len ) ); + } + + return AABB(); +} + +DVector<Face3> Light::get_faces(uint32_t p_usage_flags) const { + + return DVector<Face3>(); +} + + +void Light::set_operator(Operator p_op) { + ERR_FAIL_INDEX(p_op,2); + op=p_op; + VisualServer::get_singleton()->light_set_operator(light,VS::LightOp(op)); + +} + +Light::Operator Light::get_operator() const { + + return op; +} + +void Light::approximate_opengl_attenuation(float p_constant, float p_linear, float p_quadratic,float p_radius_treshold) { + + //this is horrible and must never be used + + float a = p_quadratic * p_radius_treshold; + float b = p_linear * p_radius_treshold; + float c = p_constant * p_radius_treshold -1; + + float radius=10000; + + if(a == 0) { // solve linear + float d = Math::abs(-c/b); + if(d<radius) + radius=d; + + + } else { // solve quadratic + // now ad^2 + bd + c = 0, solve quadratic equation: + + float denominator = 2*a; + + if(denominator != 0) { + + + float root = b*b - 4*a*c; + + if(root >=0) { + + root = sqrt(root); + + float solution1 = fabs( (-b + root) / denominator); + float solution2 = fabs( (-b - root) / denominator); + + if(solution1 > radius) + solution1 = radius; + + if(solution2 > radius) + solution2 = radius; + + radius = (solution1 > solution2 ? solution1 : solution2); + } + } + } + + float energy=1.0; + + if (p_constant>0) + energy=1.0/p_constant; //energy is this + else + energy=8.0; // some high number.. + + + if (radius==10000) + radius=100; //bug? + + set_parameter(PARAM_RADIUS,radius); + set_parameter(PARAM_ENERGY,energy); + +} + +void Light::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_parameter","variable","value"), &Light::set_parameter ); + ObjectTypeDB::bind_method(_MD("get_parameter"), &Light::get_parameter ); + ObjectTypeDB::bind_method(_MD("set_color","color","value"), &Light::set_color ); + ObjectTypeDB::bind_method(_MD("get_color"), &Light::get_color ); + ObjectTypeDB::bind_method(_MD("set_project_shadows","enable"), &Light::set_project_shadows ); + ObjectTypeDB::bind_method(_MD("has_project_shadows"), &Light::has_project_shadows ); + ObjectTypeDB::bind_method(_MD("set_projector","projector:Texture"), &Light::set_projector ); + ObjectTypeDB::bind_method(_MD("get_projector:Texture"), &Light::get_projector ); + ObjectTypeDB::bind_method(_MD("set_operator","operator"), &Light::set_operator ); + ObjectTypeDB::bind_method(_MD("get_operator"), &Light::get_operator ); + + + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/energy", PROPERTY_HINT_EXP_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ENERGY ); + /* + if (type == VisualServer::LIGHT_OMNI || type == VisualServer::LIGHT_SPOT) { + ADD_PROPERTY( PropertyInfo( Variant::REAL, "params/radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01")); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "params/attenuation", PROPERTY_HINT_RANGE, "0,8,0.01")); + } + + if (type == VisualServer::LIGHT_SPOT) { + ADD_PROPERTY( PropertyInfo( Variant::REAL, "params/spot_angle", PROPERTY_HINT_RANGE, "0.01,90.0,0.01")); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "params/spot_attenuation", PROPERTY_HINT_RANGE, "0,8,0.01")); + + }*/ + + ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/ambient"), _SCS("set_color"), _SCS("get_color"),COLOR_AMBIENT); + ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/diffuse"), _SCS("set_color"), _SCS("get_color"),COLOR_DIFFUSE); + ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/specular"), _SCS("set_color"), _SCS("get_color"),COLOR_SPECULAR); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/shadow"), _SCS("set_project_shadows"), _SCS("has_project_shadows")); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkening", PROPERTY_HINT_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_DARKENING ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_offset", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_OFFSET); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_slope_scale", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_SLOPE_SCALE); + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "projector",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_projector"), _SCS("get_projector")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "operator",PROPERTY_HINT_ENUM,"Add,Sub"), _SCS("set_operator"), _SCS("get_operator")); + + + BIND_CONSTANT( PARAM_RADIUS ); + BIND_CONSTANT( PARAM_ENERGY ); + BIND_CONSTANT( PARAM_ATTENUATION ); + BIND_CONSTANT( PARAM_SPOT_ANGLE ); + BIND_CONSTANT( PARAM_SPOT_ATTENUATION ); + BIND_CONSTANT( PARAM_SHADOW_DARKENING ); + BIND_CONSTANT( PARAM_SHADOW_Z_OFFSET ); + + BIND_CONSTANT( COLOR_AMBIENT ); + BIND_CONSTANT( COLOR_DIFFUSE ); + BIND_CONSTANT( COLOR_SPECULAR ); + +} + + +Light::Light(VisualServer::LightType p_type) { + + type=p_type; + light=VisualServer::get_singleton()->light_create(p_type); + + set_parameter(PARAM_SPOT_ATTENUATION,1.0); + set_parameter(PARAM_SPOT_ANGLE,30.0); + set_parameter(PARAM_RADIUS,2.0); + set_parameter(PARAM_ENERGY,1.0); + set_parameter(PARAM_ATTENUATION,1.0); + set_parameter(PARAM_SHADOW_DARKENING,0.0); + set_parameter(PARAM_SHADOW_Z_OFFSET,0.05); + set_parameter(PARAM_SHADOW_Z_SLOPE_SCALE,0); + + set_color( COLOR_AMBIENT, Color(0,0,0)); + set_color( COLOR_DIFFUSE, Color(1,1,1)); + set_color( COLOR_SPECULAR, Color(1,1,1)); + + op=OPERATOR_ADD; + set_project_shadows( false ); + set_base(light); + +} + + +Light::Light() { + + type=VisualServer::LIGHT_DIRECTIONAL; + ERR_PRINT("Light shouldn't be instanced dircetly, use the subtypes."); +} + + +Light::~Light() { + + if (light.is_valid()) + VisualServer::get_singleton()->free(light); +} +///////////////////////////////////////// + + +void DirectionalLight::set_shadow_mode(ShadowMode p_mode) { + + shadow_mode=p_mode; + VS::get_singleton()->light_directional_set_shadow_mode(light,(VS::LightDirectionalShadowMode)p_mode); + +} + +DirectionalLight::ShadowMode DirectionalLight::get_shadow_mode() const{ + + return shadow_mode; +} + +void DirectionalLight::set_shadow_param(ShadowParam p_param, float p_value) { + + ERR_FAIL_INDEX(p_param,3); + shadow_param[p_param]=p_value; + VS::get_singleton()->light_directional_set_shadow_param(light,VS::LightDirectionalShadowParam(p_param),p_value); +} + +float DirectionalLight::get_shadow_param(ShadowParam p_param) const { + ERR_FAIL_INDEX_V(p_param,3,0); + return shadow_param[p_param]; +} + +void DirectionalLight::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_shadow_mode","mode"),&DirectionalLight::set_shadow_mode); + ObjectTypeDB::bind_method(_MD("get_shadow_mode"),&DirectionalLight::get_shadow_mode); + ObjectTypeDB::bind_method(_MD("set_shadow_param","param","value"),&DirectionalLight::set_shadow_param); + ObjectTypeDB::bind_method(_MD("get_shadow_param","param"),&DirectionalLight::get_shadow_param); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/mode",PROPERTY_HINT_ENUM,"Orthogonal,Perspective,PSSM"),_SCS("set_shadow_mode"),_SCS("get_shadow_mode")); + ADD_PROPERTYI( PropertyInfo(Variant::REAL,"shadow/max_distance",PROPERTY_HINT_EXP_RANGE,"0.00,99999,0.01"),_SCS("set_shadow_param"),_SCS("get_shadow_param"), SHADOW_PARAM_MAX_DISTANCE); + ADD_PROPERTYI( PropertyInfo(Variant::REAL,"shadow/split_weight",PROPERTY_HINT_RANGE,"0.01,1.0,0.01"),_SCS("set_shadow_param"),_SCS("get_shadow_param"), SHADOW_PARAM_PSSM_SPLIT_WEIGHT); + ADD_PROPERTYI( PropertyInfo(Variant::REAL,"shadow/zoffset_scale",PROPERTY_HINT_RANGE,"0.01,1024.0,0.01"),_SCS("set_shadow_param"),_SCS("get_shadow_param"), SHADOW_PARAM_PSSM_ZOFFSET_SCALE); + + BIND_CONSTANT( SHADOW_ORTHOGONAL ); + BIND_CONSTANT( SHADOW_PERSPECTIVE ); + BIND_CONSTANT( SHADOW_PARALLEL_SPLIT ); + BIND_CONSTANT( SHADOW_PARAM_MAX_DISTANCE ); + BIND_CONSTANT( SHADOW_PARAM_PSSM_SPLIT_WEIGHT ); + BIND_CONSTANT( SHADOW_PARAM_PSSM_ZOFFSET_SCALE ); + +} + + +DirectionalLight::DirectionalLight() : Light( VisualServer::LIGHT_DIRECTIONAL ) { + + shadow_mode=SHADOW_ORTHOGONAL; + shadow_param[SHADOW_PARAM_MAX_DISTANCE]=0; + shadow_param[SHADOW_PARAM_PSSM_SPLIT_WEIGHT]=0.5; + shadow_param[SHADOW_PARAM_PSSM_ZOFFSET_SCALE]=2.0; + +} + + +void OmniLight::_bind_methods() { + + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/radius", PROPERTY_HINT_EXP_RANGE, "0.2,4096,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_RADIUS ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ATTENUATION ); + +} + +void SpotLight::_bind_methods() { + + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/radius", PROPERTY_HINT_EXP_RANGE, "0.2,4096,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_RADIUS ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ATTENUATION ); + + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/spot_angle", PROPERTY_HINT_RANGE, "0.01,89.9,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPOT_ANGLE ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ATTENUATION ); + +} + + diff --git a/scene/3d/light.h b/scene/3d/light.h new file mode 100644 index 0000000000..03bf336303 --- /dev/null +++ b/scene/3d/light.h @@ -0,0 +1,195 @@ +/*************************************************************************/ +/* light.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef LIGHT_H +#define LIGHT_H + + +#include "scene/3d/visual_instance.h" +#include "scene/resources/texture.h" +#include "servers/visual_server.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class Light : public VisualInstance { + + OBJ_TYPE( Light, VisualInstance ); + OBJ_CATEGORY("3D Light Nodes"); + +public: + + enum Parameter { + PARAM_RADIUS=VisualServer::LIGHT_PARAM_RADIUS, + PARAM_ENERGY=VisualServer::LIGHT_PARAM_ENERGY, + PARAM_ATTENUATION=VisualServer::LIGHT_PARAM_ATTENUATION, + PARAM_SPOT_ANGLE=VisualServer::LIGHT_PARAM_SPOT_ANGLE, + PARAM_SPOT_ATTENUATION=VisualServer::LIGHT_PARAM_ATTENUATION, + PARAM_SHADOW_DARKENING=VisualServer::LIGHT_PARAM_SHADOW_DARKENING, + PARAM_SHADOW_Z_OFFSET=VisualServer::LIGHT_PARAM_SHADOW_Z_OFFSET, + PARAM_SHADOW_Z_SLOPE_SCALE=VisualServer::LIGHT_PARAM_SHADOW_Z_SLOPE_SCALE, + PARAM_MAX=VisualServer::LIGHT_PARAM_MAX + }; + + + enum LightColor { + + COLOR_AMBIENT=VisualServer::LIGHT_COLOR_AMBIENT, + COLOR_DIFFUSE=VisualServer::LIGHT_COLOR_DIFFUSE, + COLOR_SPECULAR=VisualServer::LIGHT_COLOR_SPECULAR + }; + + + enum Operator { + + OPERATOR_ADD, + OPERATOR_SUB + }; +private: + + + Ref<Texture> projector; + float vars[PARAM_MAX]; + Color colors[3]; + + + VisualServer::LightType type; + bool shadows; + Operator op; + +// bind helpers + +protected: + + RID light; + + virtual bool _can_gizmo_scale() const; + virtual RES _get_gizmo_geometry() const; + + static void _bind_methods(); + + + Light(VisualServer::LightType p_type); +public: + + VS::LightType get_light_type() const { return type; } + + void set_parameter(Parameter p_var, float p_value); + float get_parameter(Parameter p_var) const; + + void set_color(LightColor p_color,const Color& p_value); + Color get_color(LightColor p_color) const; + + void set_project_shadows(bool p_enabled); + bool has_project_shadows() const; + + void set_projector(const Ref<Texture>& p_projector); + Ref<Texture> get_projector() const; + + void set_operator(Operator p_op); + Operator get_operator() const; + + virtual AABB get_aabb() const; + virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; + + void approximate_opengl_attenuation(float p_constant, float p_linear, float p_quadratic, float p_radius_treshold=0.5); + + Light(); + ~Light(); + +}; + +VARIANT_ENUM_CAST( Light::Parameter ); +VARIANT_ENUM_CAST( Light::LightColor ); +VARIANT_ENUM_CAST( Light::Operator ); + + +class DirectionalLight : public Light { + + OBJ_TYPE( DirectionalLight, Light ); + +public: + + enum ShadowMode { + SHADOW_ORTHOGONAL, + SHADOW_PERSPECTIVE, + SHADOW_PARALLEL_SPLIT + }; + enum ShadowParam { + SHADOW_PARAM_MAX_DISTANCE, + SHADOW_PARAM_PSSM_SPLIT_WEIGHT, + SHADOW_PARAM_PSSM_ZOFFSET_SCALE + }; + +private: + ShadowMode shadow_mode; + float shadow_param[3]; +protected: + static void _bind_methods(); +public: + + void set_shadow_mode(ShadowMode p_mode); + ShadowMode get_shadow_mode() const; + + void set_shadow_max_distance(float p_distance); + float get_shadow_max_distance() const; + void set_shadow_param(ShadowParam p_param, float p_value); + float get_shadow_param(ShadowParam p_param) const; + + DirectionalLight(); +}; + +VARIANT_ENUM_CAST( DirectionalLight::ShadowMode ); +VARIANT_ENUM_CAST( DirectionalLight::ShadowParam ); + + +class OmniLight : public Light { + + OBJ_TYPE( OmniLight, Light ); +protected: + static void _bind_methods(); + +public: + + + OmniLight() : Light( VisualServer::LIGHT_OMNI ) {} +}; + +class SpotLight : public Light { + + OBJ_TYPE( SpotLight, Light ); +protected: + static void _bind_methods(); +public: + + + SpotLight() : Light( VisualServer::LIGHT_SPOT ) {} +}; + + +#endif diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp new file mode 100644 index 0000000000..6387f5fdbc --- /dev/null +++ b/scene/3d/mesh_instance.cpp @@ -0,0 +1,218 @@ +/*************************************************************************/ +/* mesh_instance.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "mesh_instance.h" + +#include "skeleton.h" +#include "physics_body.h" + + + +bool MeshInstance::_set(const StringName& p_name, const Variant& p_value) { + + //this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else. + //add to it that it's probably found on first call to _set anyway. + + if (!get_instance().is_valid()) + return false; + + + Map<StringName,MorphTrack>::Element *E = morph_tracks.find(p_name); + if (!E) + return false; + + E->get().value=p_value; + VisualServer::get_singleton()->instance_set_morph_target_weight(get_instance(),E->get().idx,E->get().value); + + return true; +} + +bool MeshInstance::_get(const StringName& p_name,Variant &r_ret) const { + + + if (!get_instance().is_valid()) + return false; + + const Map<StringName,MorphTrack>::Element *E = morph_tracks.find(p_name); + if (!E) + return false; + + r_ret = E->get().value; + + return true; +} + +void MeshInstance::_get_property_list( List<PropertyInfo> *p_list) const { + + List<String> ls; + for(const Map<StringName,MorphTrack>::Element *E=morph_tracks.front();E;E=E->next()) { + + ls.push_back(E->key()); + } + + ls.sort();; + + for(List<String>::Element *E=ls.front();E;E=E->next()) { + p_list->push_back( PropertyInfo(Variant::REAL,E->get(),PROPERTY_HINT_RANGE,"0,1,0.01")); + } +} + + + + +void MeshInstance::set_mesh(const Ref<Mesh>& p_mesh) { + + mesh=p_mesh; + + morph_tracks.clear(); + if (mesh.is_valid()) { + + + for(int i=0;i<mesh->get_morph_target_count();i++) { + + MorphTrack mt; + mt.idx=i; + mt.value=0; + morph_tracks["morph/"+String(mesh->get_morph_target_name(i))]=mt; + } + set_base(mesh->get_rid()); + } else { + + set_base(RID()); + } + + _change_notify("mesh"); +} +Ref<Mesh> MeshInstance::get_mesh() const { + + return mesh; +} + + +AABB MeshInstance::get_aabb() const { + + if (!mesh.is_null()) + return mesh->get_aabb(); + + return AABB(); +} + +DVector<Face3> MeshInstance::get_faces(uint32_t p_usage_flags) const { + + if (!(p_usage_flags&(FACES_SOLID|FACES_ENCLOSING))) + return DVector<Face3>(); + + if (mesh.is_null()) + return DVector<Face3>(); + + return mesh->get_faces(); +} + + +Node* MeshInstance::create_trimesh_collision_node() { + + if (mesh.is_null()) + return NULL; + + Ref<Shape> shape = mesh->create_trimesh_shape(); + if (shape.is_null()) + return NULL; + + StaticBody * static_body = memnew( StaticBody ); + static_body->add_shape( shape ); + return static_body; + + return NULL; +} + +void MeshInstance::create_trimesh_collision() { + + + StaticBody* static_body = create_trimesh_collision_node()->cast_to<StaticBody>(); + ERR_FAIL_COND(!static_body); + static_body->set_name( String(get_name()) + "_col" ); + + add_child(static_body); + if (get_owner()) + static_body->set_owner( get_owner() ); + +} + +Node* MeshInstance::create_convex_collision_node() { + + if (mesh.is_null()) + return NULL; + + Ref<Shape> shape = mesh->create_convex_shape(); + if (shape.is_null()) + return NULL; + + StaticBody * static_body = memnew( StaticBody ); + static_body->add_shape( shape ); + return static_body; + + return NULL; +} + +void MeshInstance::create_convex_collision() { + + + StaticBody* static_body = create_convex_collision_node()->cast_to<StaticBody>(); + ERR_FAIL_COND(!static_body); + static_body->set_name( String(get_name()) + "_col" ); + + add_child(static_body); + if (get_owner()) + static_body->set_owner( get_owner() ); + +} + +void MeshInstance::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_mesh","mesh:Mesh"),&MeshInstance::set_mesh); + ObjectTypeDB::bind_method(_MD("get_mesh:Mesh"),&MeshInstance::get_mesh); + ObjectTypeDB::bind_method(_MD("get_aabb"),&MeshInstance::get_aabb); + ObjectTypeDB::bind_method(_MD("create_trimesh_collision"),&MeshInstance::create_trimesh_collision); + ObjectTypeDB::set_method_flags("MeshInstance","create_trimesh_collision",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + ObjectTypeDB::bind_method(_MD("create_convex_collision"),&MeshInstance::create_convex_collision); + ObjectTypeDB::set_method_flags("MeshInstance","create_convex_collision",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "mesh/mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh" ), _SCS("set_mesh"), _SCS("get_mesh")); + + +} + +MeshInstance::MeshInstance() +{ +} + + +MeshInstance::~MeshInstance() { + +} + + diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h new file mode 100644 index 0000000000..0e07109502 --- /dev/null +++ b/scene/3d/mesh_instance.h @@ -0,0 +1,80 @@ +/*************************************************************************/ +/* mesh_instance.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef MESH_INSTANCE_H +#define MESH_INSTANCE_H + +#include "scene/3d/visual_instance.h" +#include "scene/resources/mesh.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class MeshInstance : public GeometryInstance { + + OBJ_TYPE( MeshInstance, GeometryInstance ); + + Ref<Mesh> mesh; + + struct MorphTrack { + + int idx; + float value; + MorphTrack() { idx=0; value=0; } + }; + + Map<StringName,MorphTrack> morph_tracks; + + +protected: + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + + + static void _bind_methods(); +public: + + void set_mesh(const Ref<Mesh>& p_mesh); + Ref<Mesh> get_mesh() const; + + Node* create_trimesh_collision_node(); + void create_trimesh_collision(); + + Node* create_convex_collision_node(); + void create_convex_collision(); + + virtual AABB get_aabb() const; + virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; + + MeshInstance(); + ~MeshInstance(); +}; + +#endif diff --git a/scene/3d/multimesh_instance.cpp b/scene/3d/multimesh_instance.cpp new file mode 100644 index 0000000000..b4e58aca40 --- /dev/null +++ b/scene/3d/multimesh_instance.cpp @@ -0,0 +1,81 @@ +/*************************************************************************/ +/* multimesh_instance.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "multimesh_instance.h" + + + + + +void MultiMeshInstance::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_multimesh","multimesh"),&MultiMeshInstance::set_multimesh); + ObjectTypeDB::bind_method(_MD("get_multimesh"),&MultiMeshInstance::get_multimesh); + ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"multimesh",PROPERTY_HINT_RESOURCE_TYPE,"MultiMesh"), _SCS("set_multimesh"), _SCS("get_multimesh")); + + +} + +void MultiMeshInstance::set_multimesh(const Ref<MultiMesh>& p_multimesh) { + + multimesh=p_multimesh; + if (multimesh.is_valid()) + set_base(multimesh->get_rid()); + else + set_base(RID()); + +} + +Ref<MultiMesh> MultiMeshInstance::get_multimesh() const { + + return multimesh; +} + + + +DVector<Face3> MultiMeshInstance::get_faces(uint32_t p_usage_flags) const { + + return DVector<Face3>(); +} + +AABB MultiMeshInstance::get_aabb() const { + + if (multimesh.is_null()) + return AABB(); + else + return multimesh->get_aabb(); +} + +MultiMeshInstance::MultiMeshInstance() { + +} + +MultiMeshInstance::~MultiMeshInstance() { + + +} diff --git a/scene/3d/multimesh_instance.h b/scene/3d/multimesh_instance.h new file mode 100644 index 0000000000..fd50140bae --- /dev/null +++ b/scene/3d/multimesh_instance.h @@ -0,0 +1,64 @@ +/*************************************************************************/ +/* multimesh_instance.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef MULTIMESH_INSTANCE_H +#define MULTIMESH_INSTANCE_H + +#include "scene/3d/visual_instance.h" +#include "scene/resources/multimesh.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + +class MultiMeshInstance : public GeometryInstance { + OBJ_TYPE( MultiMeshInstance, GeometryInstance ); + + + Ref<MultiMesh> multimesh; +protected: + + + static void _bind_methods(); + // bind helpers + +public: + + virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; + + void set_multimesh(const Ref<MultiMesh>& p_multimesh); + Ref<MultiMesh> get_multimesh() const; + + virtual AABB get_aabb() const; + + MultiMeshInstance(); + ~MultiMeshInstance(); +}; + +#endif // MULTIMESH_INSTANCE_H + diff --git a/scene/3d/optimized_spatial_scene.cpp b/scene/3d/optimized_spatial_scene.cpp new file mode 100644 index 0000000000..12c847f71c --- /dev/null +++ b/scene/3d/optimized_spatial_scene.cpp @@ -0,0 +1,33 @@ +/*************************************************************************/ +/* optimized_spatial_scene.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "optimized_spatial_scene.h" + +OptimizedSpatialScene::OptimizedSpatialScene() +{ +} diff --git a/scene/3d/optimized_spatial_scene.h b/scene/3d/optimized_spatial_scene.h new file mode 100644 index 0000000000..36ae1ec213 --- /dev/null +++ b/scene/3d/optimized_spatial_scene.h @@ -0,0 +1,41 @@ +/*************************************************************************/ +/* optimized_spatial_scene.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef OPTIMIZED_SPATIAL_SCENE_H +#define OPTIMIZED_SPATIAL_SCENE_H + +#include "scene/3d/spatial.h" + +class OptimizedSpatialScene : public Spatial { + + OBJ_TYPE( OptimizedSpatialScene, Spatial ); +public: + OptimizedSpatialScene(); +}; + +#endif // OPTIMIZED_SPATIAL_SCENE_H diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp new file mode 100644 index 0000000000..d74768f0ab --- /dev/null +++ b/scene/3d/particles.cpp @@ -0,0 +1,559 @@ +/*************************************************************************/ +/* particles.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "particles.h" +#include "servers/visual_server.h" +#include "scene/resources/surface_tool.h" + +/* +static const char* _var_names[Particles::VAR_MAX]={ + "vars/lifetime", + "vars/spread", + "vars/gravity", + "vars/linear_vel", + "vars/angular_vel", + "vars/linear_accel", + "vars/radial_accel", + "vars/tan_accel", + "vars/initial_size", + "vars/final_size", + "vars/initial_angle", + "vars/height", + "vars/height_speed_scale", +}; +*/ +static const char* _rand_names[Particles::VAR_MAX]={ + "rand/lifetime", + "rand/spread", + "rand/gravity", + "rand/linear_vel", + "rand/angular_vel", + "rand/linear_accel", + "rand/radial_accel", + "rand/tan_accel", + "rand/damping", + "rand/initial_size", + "rand/final_size", + "rand/initial_angle", + "rand/height", + "rand/height_speed_scale", +}; + +static const Particles::Variable _var_indices[Particles::VAR_MAX]={ + Particles::VAR_LIFETIME, + Particles::VAR_SPREAD, + Particles::VAR_GRAVITY, + Particles::VAR_LINEAR_VELOCITY, + Particles::VAR_ANGULAR_VELOCITY, + Particles::VAR_LINEAR_ACCELERATION, + Particles::VAR_DRAG, + Particles::VAR_TANGENTIAL_ACCELERATION, + Particles::VAR_DAMPING, + Particles::VAR_INITIAL_SIZE, + Particles::VAR_FINAL_SIZE, + Particles::VAR_INITIAL_ANGLE, + Particles::VAR_HEIGHT, + Particles::VAR_HEIGHT_SPEED_SCALE, +}; + + + +AABB Particles::get_aabb() const { + + return AABB( Vector3(-1,-1,-1), Vector3(2, 2, 2 ) ); +} +DVector<Face3> Particles::get_faces(uint32_t p_usage_flags) const { + + return DVector<Face3>(); +} + + +void Particles::set_amount(int p_amount) { + + ERR_FAIL_INDEX(p_amount,4096); + amount=p_amount; + VisualServer::get_singleton()->particles_set_amount(particles,p_amount); +} +int Particles::get_amount() const { + + return amount; +} + +void Particles::set_emitting(bool p_emitting) { + + emitting=p_emitting; + VisualServer::get_singleton()->particles_set_emitting(particles,p_emitting); + + setup_timer(); +} +bool Particles::is_emitting() const { + + return emitting; +} + +void Particles::set_visibility_aabb(const AABB& p_aabb) { + + visibility_aabb=p_aabb; + VisualServer::get_singleton()->particles_set_visibility_aabb(particles,p_aabb); + update_gizmo(); + +} +AABB Particles::get_visibility_aabb() const { + + return visibility_aabb; +} + + +void Particles::set_emission_points(const DVector<Vector3>& p_points) { + + using_points = p_points.size(); + VisualServer::get_singleton()->particles_set_emission_points(particles,p_points); +} + +DVector<Vector3> Particles::get_emission_points() const { + + if (!using_points) + return DVector<Vector3>(); + + return VisualServer::get_singleton()->particles_get_emission_points(particles); + +} + +void Particles::set_emission_half_extents(const Vector3& p_half_extents) { + + emission_half_extents=p_half_extents; + VisualServer::get_singleton()->particles_set_emission_half_extents(particles,p_half_extents); + +} + +Vector3 Particles::get_emission_half_extents() const { + + return emission_half_extents; +} + +void Particles::set_emission_base_velocity(const Vector3& p_base_velocity) { + + emission_base_velocity=p_base_velocity; + VisualServer::get_singleton()->particles_set_emission_base_velocity(particles,p_base_velocity); + +} + +Vector3 Particles::get_emission_base_velocity() const { + + return emission_base_velocity; +} + +void Particles::set_gravity_normal(const Vector3& p_normal) { + + gravity_normal=p_normal; + VisualServer::get_singleton()->particles_set_gravity_normal(particles,p_normal); +} + +Vector3 Particles::get_gravity_normal() const { + + return gravity_normal; + +} + +void Particles::set_variable(Variable p_variable,float p_value) { + + ERR_FAIL_INDEX(p_variable,VAR_MAX); + var[p_variable]=p_value; + VisualServer::get_singleton()->particles_set_variable(particles,(VS::ParticleVariable)p_variable,p_value); + if (p_variable==VAR_SPREAD) + update_gizmo(); +} + +float Particles::get_variable(Variable p_variable) const { + + ERR_FAIL_INDEX_V(p_variable,VAR_MAX,-1); + return var[p_variable]; + +} + +void Particles::set_randomness(Variable p_variable,float p_randomness) { + + ERR_FAIL_INDEX(p_variable,VAR_MAX); + var_random[p_variable]=p_randomness; + VisualServer::get_singleton()->particles_set_randomness(particles,(VS::ParticleVariable)p_variable,p_randomness); + +} +float Particles::get_randomness(Variable p_variable) const { + + ERR_FAIL_INDEX_V(p_variable,VAR_MAX,-1); + return var_random[p_variable]; + +} + +void Particles::set_color_phase_pos(int p_phase, float p_pos) { + + ERR_FAIL_INDEX(p_phase,VS::MAX_PARTICLE_COLOR_PHASES); + color_phase[p_phase].pos=p_pos; + VisualServer::get_singleton()->particles_set_color_phase_pos(particles,p_phase,p_pos); + +} +float Particles::get_color_phase_pos(int p_phase) const { + + ERR_FAIL_INDEX_V(p_phase,VS::MAX_PARTICLE_COLOR_PHASES,-1); + return color_phase[p_phase].pos; +} + +void Particles::set_color_phase_color(int p_phase, const Color& p_color) { + + ERR_FAIL_INDEX(p_phase,VS::MAX_PARTICLE_COLOR_PHASES); + color_phase[p_phase].color=p_color; + VisualServer::get_singleton()->particles_set_color_phase_color(particles,p_phase,p_color); + +} +Color Particles::get_color_phase_color(int p_phase) const { + + ERR_FAIL_INDEX_V(p_phase,VS::MAX_PARTICLE_COLOR_PHASES,Color()); + return color_phase[p_phase].color; + +} + +void Particles::set_material(const Ref<Material>& p_material) { + + material=p_material; + if(material.is_null()) { + VisualServer::get_singleton()->particles_set_material(particles,RID()); + } else { + VisualServer::get_singleton()->particles_set_material(particles,material->get_rid()); + } + +} + +void Particles::setup_timer() { + + if (emitting && emit_timeout > 0) { + + timer->set_wait_time(emit_timeout); + timer->start(); + timer->set_one_shot(true); + }; +}; + +void Particles::set_emit_timeout(float p_timeout) { + + emit_timeout = p_timeout; + setup_timer(); +}; + +float Particles::get_emit_timeout() const { + + return emit_timeout; +}; + + +Ref<Material> Particles::get_material() const { + + return material; +} + +void Particles::set_height_from_velocity(bool p_enable) { + + height_from_velocity=p_enable; + VisualServer::get_singleton()->particles_set_height_from_velocity(particles,height_from_velocity); +} + +bool Particles::has_height_from_velocity() const { + + return height_from_velocity; +} + +void Particles::set_color_phases(int p_phases) { + + color_phase_count=p_phases; + VisualServer::get_singleton()->particles_set_color_phases(particles,p_phases); +} + +int Particles::get_color_phases() const{ + + return color_phase_count; +} + +bool Particles::_can_gizmo_scale() const { + + return false; +} + +void Particles::set_use_local_coordinates(bool p_use) { + + local_coordinates=p_use; + VisualServer::get_singleton()->particles_set_use_local_coordinates(particles,local_coordinates); +} + +bool Particles::is_using_local_coordinates() const{ + + return local_coordinates; +} + + +RES Particles::_get_gizmo_geometry() const { + + Ref<SurfaceTool> surface_tool( memnew( SurfaceTool )); + + Ref<FixedMaterial> mat( memnew( FixedMaterial )); + + mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.0,0.6,0.7,0.2) ); + mat->set_parameter( FixedMaterial::PARAM_EMISSION,Color(0.5,0.7,0.8) ); + mat->set_blend_mode( Material::BLEND_MODE_ADD ); + mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); + mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true); + + + surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES); + surface_tool->set_material(mat); + + int sides=16; + int sections=24; + +// float len=1; + float deg=Math::deg2rad(var[VAR_SPREAD]*180); + if (deg==180) + deg=179.5; + + Vector3 to=Vector3(0,0,-1); + + for(int j=0;j<sections;j++) { + + Vector3 p1=Matrix3(Vector3(1,0,0),deg*j/sections).xform(to); + Vector3 p2=Matrix3(Vector3(1,0,0),deg*(j+1)/sections).xform(to); + + for(int i=0;i<sides;i++) { + + Vector3 p1r = Matrix3(Vector3(0,0,1),Math_PI*2*float(i)/sides).xform(p1); + Vector3 p1s = Matrix3(Vector3(0,0,1),Math_PI*2*float(i+1)/sides).xform(p1); + Vector3 p2s = Matrix3(Vector3(0,0,1),Math_PI*2*float(i+1)/sides).xform(p2); + Vector3 p2r = Matrix3(Vector3(0,0,1),Math_PI*2*float(i)/sides).xform(p2); + + surface_tool->add_normal(p1r.normalized()); + surface_tool->add_vertex(p1r); + surface_tool->add_normal(p1s.normalized()); + surface_tool->add_vertex(p1s); + surface_tool->add_normal(p2s.normalized()); + surface_tool->add_vertex(p2s); + + surface_tool->add_normal(p1r.normalized()); + surface_tool->add_vertex(p1r); + surface_tool->add_normal(p2s.normalized()); + surface_tool->add_vertex(p2s); + surface_tool->add_normal(p2r.normalized()); + surface_tool->add_vertex(p2r); + + if (j==sections-1) { + + surface_tool->add_normal(p2r.normalized()); + surface_tool->add_vertex(p2r); + surface_tool->add_normal(p2s.normalized()); + surface_tool->add_vertex(p2s); + surface_tool->add_normal(Vector3(0,0,1)); + surface_tool->add_vertex(Vector3()); + } + } + } + + + Ref<Mesh> mesh = surface_tool->commit(); + + Ref<FixedMaterial> mat_aabb( memnew( FixedMaterial )); + + mat_aabb->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.9,0.7) ); + mat_aabb->set_line_width(3); + mat_aabb->set_flag( Material::FLAG_UNSHADED, true ); + + surface_tool->begin(Mesh::PRIMITIVE_LINES); + surface_tool->set_material(mat_aabb); + + for(int i=0;i<12;i++) { + + Vector3 f,t; + visibility_aabb.get_edge(i,f,t); + surface_tool->add_vertex(f); + surface_tool->add_vertex(t); + } + + return surface_tool->commit(mesh); + +} + + +void Particles::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_amount","amount"),&Particles::set_amount); + ObjectTypeDB::bind_method(_MD("get_amount"),&Particles::get_amount); + ObjectTypeDB::bind_method(_MD("set_emitting","enabled"),&Particles::set_emitting); + ObjectTypeDB::bind_method(_MD("is_emitting"),&Particles::is_emitting); + ObjectTypeDB::bind_method(_MD("set_visibility_aabb","aabb"),&Particles::set_visibility_aabb); + ObjectTypeDB::bind_method(_MD("get_visibility_aabb"),&Particles::get_visibility_aabb); + ObjectTypeDB::bind_method(_MD("set_emission_half_extents","half_extents"),&Particles::set_emission_half_extents); + ObjectTypeDB::bind_method(_MD("get_emission_half_extents"),&Particles::get_emission_half_extents); + ObjectTypeDB::bind_method(_MD("set_emission_base_velocity","base_velocity"),&Particles::set_emission_base_velocity); + ObjectTypeDB::bind_method(_MD("get_emission_base_velocity"),&Particles::get_emission_base_velocity); + ObjectTypeDB::bind_method(_MD("set_emission_points","points"),&Particles::set_emission_points); + ObjectTypeDB::bind_method(_MD("get_emission_points"),&Particles::get_emission_points); + ObjectTypeDB::bind_method(_MD("set_gravity_normal","normal"),&Particles::set_gravity_normal); + ObjectTypeDB::bind_method(_MD("get_gravity_normal"),&Particles::get_gravity_normal); + ObjectTypeDB::bind_method(_MD("set_variable","variable","value"),&Particles::set_variable); + ObjectTypeDB::bind_method(_MD("get_variable","variable"),&Particles::get_variable); + ObjectTypeDB::bind_method(_MD("set_randomness","variable","randomness"),&Particles::set_randomness); + ObjectTypeDB::bind_method(_MD("get_randomness"),&Particles::get_randomness); + ObjectTypeDB::bind_method(_MD("set_color_phase_pos","phase","pos"),&Particles::set_color_phase_pos); + ObjectTypeDB::bind_method(_MD("get_color_phase_pos","phase"),&Particles::get_color_phase_pos); + ObjectTypeDB::bind_method(_MD("set_color_phase_color","phase","color"),&Particles::set_color_phase_color); + ObjectTypeDB::bind_method(_MD("get_color_phase_color","phase"),&Particles::get_color_phase_color); + ObjectTypeDB::bind_method(_MD("set_material","material:Material"),&Particles::set_material); + ObjectTypeDB::bind_method(_MD("get_material:Material"),&Particles::get_material); + ObjectTypeDB::bind_method(_MD("set_emit_timeout"),&Particles::set_emit_timeout); + ObjectTypeDB::bind_method(_MD("get_emit_timeout"),&Particles::get_emit_timeout); + ObjectTypeDB::bind_method(_MD("set_height_from_velocity","enable"),&Particles::set_height_from_velocity); + ObjectTypeDB::bind_method(_MD("has_height_from_velocity"),&Particles::has_height_from_velocity); + ObjectTypeDB::bind_method(_MD("set_use_local_coordinates","enable"),&Particles::set_use_local_coordinates); + ObjectTypeDB::bind_method(_MD("is_using_local_coordinates"),&Particles::is_using_local_coordinates); + + ObjectTypeDB::bind_method(_MD("set_color_phases","count"),&Particles::set_color_phases); + ObjectTypeDB::bind_method(_MD("get_color_phases"),&Particles::get_color_phases); + + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "Material" ), _SCS("set_material"), _SCS("get_material") ); + + ADD_PROPERTY( PropertyInfo( Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,4096,1" ), _SCS("set_amount"), _SCS("get_amount") ); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "emitting" ), _SCS("set_emitting"), _SCS("is_emitting") ); + ADD_PROPERTY( PropertyInfo( Variant::_AABB, "visibility" ), _SCS("set_visibility_aabb"), _SCS("get_visibility_aabb") ); + ADD_PROPERTY( PropertyInfo( Variant::VECTOR3, "emission_extents" ), _SCS("set_emission_half_extents"), _SCS("get_emission_half_extents") ); + ADD_PROPERTY( PropertyInfo( Variant::VECTOR3, "emission_base_velocity" ), _SCS("set_emission_base_velocity"), _SCS("get_emission_base_velocity") ); + ADD_PROPERTY( PropertyInfo( Variant::VECTOR3_ARRAY, "emission_points" ), _SCS("set_emission_points"), _SCS("get_emission_points") ); + ADD_PROPERTY( PropertyInfo( Variant::VECTOR3, "gravity_normal" ), _SCS("set_gravity_normal"), _SCS("get_gravity_normal") ); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "local_coords" ), _SCS("set_use_local_coordinates"), _SCS("is_using_local_coordinates") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "emit_timeout",PROPERTY_HINT_RANGE,"0,256,0.01"), _SCS("set_emit_timeout"), _SCS("get_emit_timeout") ); + + + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/lifetime", PROPERTY_HINT_RANGE,"0.1,60,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_LIFETIME ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/spread", PROPERTY_HINT_RANGE,"0,1,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_SPREAD ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/gravity", PROPERTY_HINT_RANGE,"-48,48,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_GRAVITY ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/linear_vel", PROPERTY_HINT_RANGE,"-100,100,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_LINEAR_VELOCITY ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/angular_vel", PROPERTY_HINT_RANGE,"-100,100,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_ANGULAR_VELOCITY ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/linear_accel", PROPERTY_HINT_RANGE,"-100,100,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_LINEAR_ACCELERATION ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/radial_accel", PROPERTY_HINT_RANGE,"-100,100,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_DRAG ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/tan_accel", PROPERTY_HINT_RANGE,"-100,100,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_TANGENTIAL_ACCELERATION ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/damping", PROPERTY_HINT_RANGE,"0,128,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_DAMPING ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/initial_size", PROPERTY_HINT_RANGE,"0,100,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_INITIAL_SIZE ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/final_size", PROPERTY_HINT_RANGE,"0,100,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_FINAL_SIZE ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/initial_angle",PROPERTY_HINT_RANGE,"0,1,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_INITIAL_ANGLE ); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "vars/height_from_velocity"), _SCS("set_height_from_velocity"), _SCS("has_height_from_velocity") ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/height",PROPERTY_HINT_RANGE,"0,4096,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_HEIGHT); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/height_speed_scale",PROPERTY_HINT_RANGE,"0,4096,0.01"), _SCS("set_variable"), _SCS("get_variable"), VAR_HEIGHT_SPEED_SCALE ); + + for(int i=0;i<VAR_MAX;i++) + ADD_PROPERTYI( PropertyInfo( Variant::REAL, _rand_names[i], PROPERTY_HINT_RANGE,"-16.0,16.0,0.01"),_SCS("set_randomness"), _SCS("get_randomness"),_var_indices[i] ); + + + ADD_PROPERTY( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1"), _SCS("set_color_phases"), _SCS("get_color_phases")); + + for(int i=0;i<VS::MAX_PARTICLE_COLOR_PHASES;i++) { + String phase="phase_"+itos(i)+"/"; + ADD_PROPERTYI( PropertyInfo( Variant::REAL, phase+"pos", PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_color_phase_pos"),_SCS("get_color_phase_pos"),i ); + ADD_PROPERTYI( PropertyInfo( Variant::COLOR, phase+"color"),_SCS("set_color_phase_color"),_SCS("get_color_phase_color"),i ); + } + + BIND_CONSTANT( VAR_LIFETIME ); + BIND_CONSTANT( VAR_SPREAD ); + BIND_CONSTANT( VAR_GRAVITY ); + BIND_CONSTANT( VAR_LINEAR_VELOCITY ); + BIND_CONSTANT( VAR_ANGULAR_VELOCITY ); + BIND_CONSTANT( VAR_LINEAR_ACCELERATION ); + BIND_CONSTANT( VAR_DRAG ); + BIND_CONSTANT( VAR_TANGENTIAL_ACCELERATION ); + BIND_CONSTANT( VAR_INITIAL_SIZE ); + BIND_CONSTANT( VAR_FINAL_SIZE ); + BIND_CONSTANT( VAR_INITIAL_ANGLE ); + BIND_CONSTANT( VAR_HEIGHT ); + BIND_CONSTANT( VAR_HEIGHT_SPEED_SCALE ); + BIND_CONSTANT( VAR_MAX ); + +} + +Particles::Particles() { + + particles = VisualServer::get_singleton()->particles_create(); + timer = memnew(Timer); + add_child(timer); + emit_timeout = 0; + + set_amount(64); + set_emitting(true); + set_visibility_aabb(AABB( Vector3(-4,-4,-4), Vector3(8,8,8) ) ); + + for (int i=0;i<VAR_MAX;i++) { + set_randomness((Variable)i,0.0); + } + + set_variable( VAR_LIFETIME, 5.0); + set_variable( VAR_SPREAD, 0.2); + set_variable( VAR_GRAVITY, 9.8); + set_variable( VAR_LINEAR_VELOCITY, 0.2); + set_variable( VAR_ANGULAR_VELOCITY, 0.0); + set_variable( VAR_LINEAR_ACCELERATION, 0.0); + set_variable( VAR_DRAG, 0.0); + set_variable( VAR_TANGENTIAL_ACCELERATION, 0.0); + set_variable( VAR_DAMPING, 0.0); + set_variable( VAR_INITIAL_SIZE, 1.0); + set_variable( VAR_FINAL_SIZE, 1.0); + set_variable( VAR_INITIAL_ANGLE, 0.0); + set_variable( VAR_HEIGHT, 1.0); + set_variable( VAR_HEIGHT_SPEED_SCALE, 0.0); + + color_phase_count=0; + + set_color_phase_pos(0,0.0); + set_color_phase_pos(1,1.0); + set_color_phase_pos(2,1.0); + set_color_phase_pos(3,1.0); + + set_color_phase_color(0,Color(1,1,1)); + set_color_phase_color(1,Color(0,0,0)); + set_color_phase_color(2,Color(0,0,0)); + set_color_phase_color(3,Color(0,0,0)); + + set_gravity_normal(Vector3(0,-1.0,0)); + set_emission_half_extents(Vector3(0.1,0.1,0.1)); + + height_from_velocity=false; + + Vector<Variant> pars; + pars.push_back(false); + timer->connect("timeout", this, "set_emitting", pars); + set_base(particles); + local_coordinates=false; +} + + +Particles::~Particles() { + + VisualServer::get_singleton()->free(particles); +} + diff --git a/scene/3d/particles.h b/scene/3d/particles.h new file mode 100644 index 0000000000..40d569d7b4 --- /dev/null +++ b/scene/3d/particles.h @@ -0,0 +1,165 @@ +/*************************************************************************/ +/* particles.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef VISUALINSTANCEPARTICLES_H +#define VISUALINSTANCEPARTICLES_H + +#include "scene/3d/visual_instance.h" +#include "scene/resources/material.h" +#include "scene/main/timer.h" +#include "rid.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + +class Particles : public GeometryInstance { +public: + + enum Variable { + VAR_LIFETIME=VS::PARTICLE_LIFETIME, + VAR_SPREAD=VS::PARTICLE_SPREAD, + VAR_GRAVITY=VS::PARTICLE_GRAVITY, + VAR_LINEAR_VELOCITY=VS::PARTICLE_LINEAR_VELOCITY, + VAR_ANGULAR_VELOCITY=VS::PARTICLE_ANGULAR_VELOCITY, + VAR_LINEAR_ACCELERATION=VS::PARTICLE_LINEAR_ACCELERATION, + VAR_DRAG=VS::PARTICLE_RADIAL_ACCELERATION, + VAR_TANGENTIAL_ACCELERATION=VS::PARTICLE_TANGENTIAL_ACCELERATION, + VAR_DAMPING=VS::PARTICLE_DAMPING, + VAR_INITIAL_SIZE=VS::PARTICLE_INITIAL_SIZE, + VAR_FINAL_SIZE=VS::PARTICLE_FINAL_SIZE, + VAR_INITIAL_ANGLE=VS::PARTICLE_INITIAL_ANGLE, + VAR_HEIGHT=VS::PARTICLE_HEIGHT, + VAR_HEIGHT_SPEED_SCALE=VS::PARTICLE_HEIGHT_SPEED_SCALE, + VAR_MAX=VS::PARTICLE_VAR_MAX + }; + +private: + OBJ_TYPE( Particles, GeometryInstance ); + + RID particles; + + int amount; + bool emitting; + float emit_timeout; + AABB visibility_aabb; + Vector3 gravity_normal; + Vector3 emission_half_extents; + bool using_points; + float var[VAR_MAX]; + float var_random[VAR_MAX]; + bool height_from_velocity; + Vector3 emission_base_velocity; + bool local_coordinates; + + struct ColorPhase { + + Color color; + float pos; + }; + + virtual bool _can_gizmo_scale() const; + virtual RES _get_gizmo_geometry() const; + + int color_phase_count; + + ColorPhase color_phase[4]; + + Ref<Material> material; + + Timer* timer; + void setup_timer(); + +protected: + + static void _bind_methods(); + +public: + + + AABB get_aabb() const; + DVector<Face3> get_faces(uint32_t p_usage_flags) const; + + void set_amount(int p_amount); + int get_amount() const; + + void set_emitting(bool p_emitting); + bool is_emitting() const; + + void set_visibility_aabb(const AABB& p_aabb); + AABB get_visibility_aabb() const; + + void set_emission_half_extents(const Vector3& p_half_extents); + Vector3 get_emission_half_extents() const; + + void set_emission_base_velocity(const Vector3& p_base_velocity); + Vector3 get_emission_base_velocity() const; + + void set_emission_points(const DVector<Vector3>& p_points); + DVector<Vector3> get_emission_points() const; + + void set_gravity_normal(const Vector3& p_normal); + Vector3 get_gravity_normal() const; + + void set_variable(Variable p_variable,float p_value); + float get_variable(Variable p_variable) const; + + void set_randomness(Variable p_variable,float p_randomness); + float get_randomness(Variable p_variable) const; + + void set_color_phases(int p_phases); + int get_color_phases() const; + + void set_color_phase_pos(int p_phase, float p_pos); + float get_color_phase_pos(int p_phase) const; + + void set_color_phase_color(int p_phase, const Color& p_color); + Color get_color_phase_color(int p_phase) const; + + void set_height_from_velocity(bool p_enable); + bool has_height_from_velocity() const; + + void set_material(const Ref<Material>& p_material); + Ref<Material> get_material() const; + + void set_emit_timeout(float p_timeout); + float get_emit_timeout() const; + + void set_use_local_coordinates(bool p_use); + bool is_using_local_coordinates() const; + + void start_emitting(float p_time); + + + Particles(); + ~Particles(); + +}; + +VARIANT_ENUM_CAST( Particles::Variable ); +#endif diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp new file mode 100644 index 0000000000..bc5cb1c4a2 --- /dev/null +++ b/scene/3d/path.cpp @@ -0,0 +1,388 @@ +/*************************************************************************/ +/* path.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "path.h"
+#include "scene/scene_string_names.h"
+
+void Path::_notification(int p_what) {
+#if 0
+ if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_scene() && get_scene()->is_editor_hint()) {
+ //draw the curve!!
+
+ for(int i=0;i<curve->get_point_count();i++) {
+
+ Vector2 prev_p=curve->get_point_pos(i);
+
+ for(int j=1;j<=8;j++) {
+
+ real_t frac = j/8.0;
+ Vector2 p = curve->interpolate(i,frac);
+ draw_line(prev_p,p,Color(0.5,0.6,1.0,0.7),2);
+ prev_p=p;
+ }
+ }
+ }
+#endif
+}
+
+void Path::_curve_changed() {
+
+
+ if (is_inside_scene() && get_scene()->is_editor_hint())
+ update_gizmo();
+}
+
+
+void Path::set_curve(const Ref<Curve3D>& p_curve) {
+
+ if (curve.is_valid()) {
+ curve->disconnect("changed",this,"_curve_changed");
+ }
+
+ curve=p_curve;
+
+ if (curve.is_valid()) {
+ curve->connect("changed",this,"_curve_changed");
+ }
+ _curve_changed();
+
+}
+
+Ref<Curve3D> Path::get_curve() const{
+
+ return curve;
+}
+
+void Path::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_curve","curve:Curve3D"),&Path::set_curve);
+ ObjectTypeDB::bind_method(_MD("get_curve:Curve3D","curve"),&Path::get_curve);
+ ObjectTypeDB::bind_method(_MD("_curve_changed"),&Path::_curve_changed);
+
+ ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), _SCS("set_curve"),_SCS("get_curve"));
+}
+
+Path::Path() {
+
+ set_curve(Ref<Curve3D>( memnew( Curve3D ))); //create one by default
+}
+
+
+//////////////
+
+
+void PathFollow::_update_transform() {
+
+
+ if (!path)
+ return;
+
+ Ref<Curve3D> c =path->get_curve();
+ if (!c.is_valid())
+ return;
+
+
+ float o = offset;
+ if (loop)
+ o=Math::fposmod(o,c->get_baked_length());
+
+ Vector3 pos = c->interpolate_baked(o,cubic);
+ Transform t=get_transform();
+
+
+ if (rotation_mode!=ROTATION_NONE) {
+
+ Vector3 n = (c->interpolate_baked(o+lookahead,cubic)-pos).normalized();
+
+ if (rotation_mode==ROTATION_Y) {
+
+ n.y=0;
+ n.normalize();
+ }
+
+ if (n.length()<CMP_EPSILON) {//nothing, use previous
+ n=-t.get_basis().get_axis(2).normalized();
+ }
+
+
+ Vector3 up = Vector3(0,1,0);
+
+ if (rotation_mode==ROTATION_XYZ) {
+
+ float tilt = c->interpolate_baked_tilt(o);
+ if (tilt!=0) {
+
+ Matrix3 rot(-n,tilt); //remember.. lookat will be znegative.. znegative!! we abide by opengl clan.
+ up=rot.xform(up);
+ }
+ }
+
+ t.set_look_at(pos,pos+n,up);
+
+ } else {
+
+ t.origin=pos;
+ }
+
+ t.origin+=t.basis.get_axis(0)*h_offset + t.basis.get_axis(1)*v_offset;
+ set_transform(t);
+
+}
+
+void PathFollow::_notification(int p_what) {
+
+
+ switch(p_what) {
+
+ case NOTIFICATION_ENTER_SCENE: {
+
+ Node *parent=get_parent();
+ if (parent) {
+
+ path=parent->cast_to<Path>();
+ if (path) {
+ _update_transform();
+ }
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_SCENE: {
+
+
+ path=NULL;
+ } break;
+ }
+
+}
+
+void PathFollow::set_cubic_interpolation(bool p_enable) {
+
+ cubic=p_enable;
+}
+
+bool PathFollow::get_cubic_interpolation() const {
+
+ return cubic;
+}
+
+
+bool PathFollow::_set(const StringName& p_name, const Variant& p_value) {
+
+ if (p_name==SceneStringNames::get_singleton()->offset) {
+ set_offset(p_value);
+ } else if (p_name==SceneStringNames::get_singleton()->unit_offset) {
+ set_unit_offset(p_value);
+ } else if (p_name==SceneStringNames::get_singleton()->rotation_mode) {
+ set_rotation_mode(RotationMode(p_value.operator int()));
+ } else if (p_name==SceneStringNames::get_singleton()->v_offset) {
+ set_v_offset(p_value);
+ } else if (p_name==SceneStringNames::get_singleton()->h_offset) {
+ set_h_offset(p_value);
+ } else if (String(p_name)=="cubic_interp") {
+ set_cubic_interpolation(p_value);
+ } else if (String(p_name)=="loop") {
+ set_loop(p_value);
+ } else if (String(p_name)=="lookahead") {
+ set_lookahead(p_value);
+ } else
+ return false;
+
+ return true;
+}
+
+bool PathFollow::_get(const StringName& p_name,Variant &r_ret) const{
+
+ if (p_name==SceneStringNames::get_singleton()->offset) {
+ r_ret=get_offset();
+ } else if (p_name==SceneStringNames::get_singleton()->unit_offset) {
+ r_ret=get_unit_offset();
+ } else if (p_name==SceneStringNames::get_singleton()->rotation_mode) {
+ r_ret=get_rotation_mode();
+ } else if (p_name==SceneStringNames::get_singleton()->v_offset) {
+ r_ret=get_v_offset();
+ } else if (p_name==SceneStringNames::get_singleton()->h_offset) {
+ r_ret=get_h_offset();
+ } else if (String(p_name)=="cubic_interp") {
+ r_ret=cubic;
+ } else if (String(p_name)=="loop") {
+ r_ret=loop;
+ } else if (String(p_name)=="lookahead") {
+ r_ret=lookahead;
+ } else
+ return false;
+
+ return true;
+
+}
+void PathFollow::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ float max=10000;
+ if (path && path->get_curve().is_valid())
+ max=path->get_curve()->get_baked_length();
+ p_list->push_back( PropertyInfo( Variant::REAL, "offset", PROPERTY_HINT_RANGE,"0,"+rtos(max)+",0.01"));
+ p_list->push_back( PropertyInfo( Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE,"0,1,0.0001",PROPERTY_USAGE_EDITOR));
+ p_list->push_back( PropertyInfo( Variant::REAL, "h_offset") );
+ p_list->push_back( PropertyInfo( Variant::REAL, "v_offset") );
+ p_list->push_back( PropertyInfo( Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM,"None,Y,XY,XYZ"));
+ p_list->push_back( PropertyInfo( Variant::BOOL, "cubic_interp"));
+ p_list->push_back( PropertyInfo( Variant::BOOL, "loop"));
+ p_list->push_back( PropertyInfo( Variant::REAL, "lookahead",PROPERTY_HINT_RANGE,"0.001,1024.0,0.001"));
+}
+
+
+void PathFollow::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_offset","offset"),&PathFollow::set_offset);
+ ObjectTypeDB::bind_method(_MD("get_offset"),&PathFollow::get_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_h_offset","h_offset"),&PathFollow::set_h_offset);
+ ObjectTypeDB::bind_method(_MD("get_h_offset"),&PathFollow::get_h_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_v_offset","v_offset"),&PathFollow::set_v_offset);
+ ObjectTypeDB::bind_method(_MD("get_v_offset"),&PathFollow::get_v_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_unit_offset","unit_offset"),&PathFollow::set_unit_offset);
+ ObjectTypeDB::bind_method(_MD("get_unit_offset"),&PathFollow::get_unit_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_rotation_mode","rotation_mode"),&PathFollow::set_rotation_mode);
+ ObjectTypeDB::bind_method(_MD("get_rotation_mode"),&PathFollow::get_rotation_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_cubic_interpolation","enable"),&PathFollow::set_cubic_interpolation);
+ ObjectTypeDB::bind_method(_MD("get_cubic_interpolation"),&PathFollow::get_cubic_interpolation);
+
+ ObjectTypeDB::bind_method(_MD("set_loop","loop"),&PathFollow::set_loop);
+ ObjectTypeDB::bind_method(_MD("has_loop"),&PathFollow::has_loop);
+
+ BIND_CONSTANT( ROTATION_NONE );
+ BIND_CONSTANT( ROTATION_Y );
+ BIND_CONSTANT( ROTATION_XY );
+ BIND_CONSTANT( ROTATION_XYZ );
+
+}
+
+void PathFollow::set_offset(float p_offset) {
+
+ offset=p_offset;
+ if (path)
+ _update_transform();
+ _change_notify("offset");
+ _change_notify("unit_offset");
+
+}
+
+void PathFollow::set_h_offset(float p_h_offset) {
+
+ h_offset=p_h_offset;
+ if (path)
+ _update_transform();
+
+}
+
+float PathFollow::get_h_offset() const {
+
+ return h_offset;
+}
+
+void PathFollow::set_v_offset(float p_v_offset) {
+
+ v_offset=p_v_offset;
+ if (path)
+ _update_transform();
+
+}
+
+float PathFollow::get_v_offset() const {
+
+ return v_offset;
+}
+
+
+float PathFollow::get_offset() const{
+
+ return offset;
+}
+
+void PathFollow::set_unit_offset(float p_unit_offset) {
+
+ if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length())
+ set_offset(p_unit_offset*path->get_curve()->get_baked_length());
+
+}
+
+float PathFollow::get_unit_offset() const{
+
+ if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length())
+ return get_offset()/path->get_curve()->get_baked_length();
+ else
+ return 0;
+}
+
+void PathFollow::set_lookahead(float p_lookahead) {
+
+ lookahead=p_lookahead;
+
+}
+
+float PathFollow::get_lookahead() const{
+
+ return lookahead;
+}
+
+void PathFollow::set_rotation_mode(RotationMode p_rotation_mode) {
+
+ rotation_mode=p_rotation_mode;
+ _update_transform();
+}
+
+PathFollow::RotationMode PathFollow::get_rotation_mode() const {
+
+ return rotation_mode;
+}
+
+void PathFollow::set_loop(bool p_loop) {
+
+ loop=p_loop;
+}
+
+bool PathFollow::has_loop() const{
+
+ return loop;
+}
+
+
+PathFollow::PathFollow() {
+
+ offset=0;
+ h_offset=0;
+ v_offset=0;
+ path=NULL;
+ rotation_mode=ROTATION_XYZ;
+ cubic=true;
+ loop=true;
+ lookahead=0.1;
+}
diff --git a/scene/3d/path.h b/scene/3d/path.h new file mode 100644 index 0000000000..6f907265ba --- /dev/null +++ b/scene/3d/path.h @@ -0,0 +1,122 @@ +/*************************************************************************/ +/* path.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef PATH_H
+#define PATH_H
+
+#include "scene/resources/curve.h"
+#include "scene/3d/spatial.h"
+
+class Path : public Spatial {
+
+ OBJ_TYPE( Path, Spatial );
+
+ Ref<Curve3D> curve;
+
+ void _curve_changed();
+
+
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_curve(const Ref<Curve3D>& p_curve);
+ Ref<Curve3D> get_curve() const;
+
+
+ Path();
+};
+
+class PathFollow : public Spatial {
+
+ OBJ_TYPE(PathFollow,Spatial);
+public:
+
+ enum RotationMode {
+
+ ROTATION_NONE,
+ ROTATION_Y,
+ ROTATION_XY,
+ ROTATION_XYZ
+ };
+
+private:
+ Path *path;
+ real_t offset;
+ real_t h_offset;
+ real_t v_offset;
+ real_t lookahead;
+ bool cubic;
+ bool loop;
+ RotationMode rotation_mode;
+
+ void _update_transform();
+
+
+protected:
+
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_offset(float p_offset);
+ float get_offset() const;
+
+ void set_h_offset(float p_h_offset);
+ float get_h_offset() const;
+
+ void set_v_offset(float p_v_offset);
+ float get_v_offset() const;
+
+ void set_unit_offset(float p_unit_offset);
+ float get_unit_offset() const;
+
+ void set_lookahead(float p_lookahead);
+ float get_lookahead() const;
+
+ void set_loop(bool p_loop);
+ bool has_loop() const;
+
+ void set_rotation_mode(RotationMode p_rotation_mode);
+ RotationMode get_rotation_mode() const;
+
+ void set_cubic_interpolation(bool p_enable);
+ bool get_cubic_interpolation() const;
+
+ PathFollow();
+};
+
+VARIANT_ENUM_CAST(PathFollow::RotationMode);
+
+#endif // PATH_H
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp new file mode 100644 index 0000000000..e42a96cc4e --- /dev/null +++ b/scene/3d/physics_body.cpp @@ -0,0 +1,741 @@ +/*************************************************************************/ +/* physics_body.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "physics_body.h" +#include "scene/scene_string_names.h" + +void PhysicsBody::_notification(int p_what) { + +/* + switch(p_what) { + + case NOTIFICATION_TRANSFORM_CHANGED: { + + PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform()); + + } break; + } + */ +} + +PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : CollisionObject( PhysicsServer::get_singleton()->body_create(p_mode), false) { + + + +} + +void StaticBody::set_constant_linear_velocity(const Vector3& p_vel) { + + constant_linear_velocity=p_vel; + PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_LINEAR_VELOCITY,constant_linear_velocity); + +} + +void StaticBody::set_constant_angular_velocity(const Vector3& p_vel) { + + constant_angular_velocity=p_vel; + PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_ANGULAR_VELOCITY,constant_angular_velocity); +} + +Vector3 StaticBody::get_constant_linear_velocity() const { + + return constant_linear_velocity; +} +Vector3 StaticBody::get_constant_angular_velocity() const { + + return constant_angular_velocity; +} + + +void StaticBody::_state_notify(Object *p_object) { + + if (!pre_xform) + return; + + PhysicsDirectBodyState *p2d = (PhysicsDirectBodyState*)p_object; + setting=true; + + Transform new_xform = p2d->get_transform(); + *pre_xform=new_xform; + set_ignore_transform_notification(true); + set_global_transform(new_xform); + set_ignore_transform_notification(false); + + setting=false; + + +} + +void StaticBody::_update_xform() { + + if (!pre_xform || !pending) + return; + + setting=true; + + + Transform new_xform = get_global_transform(); //obtain the new one + + //set_block_transform_notify(true); + set_ignore_transform_notification(true); + PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_TRANSFORM,*pre_xform); //then simulate motion! + set_global_transform(*pre_xform); //but restore state to previous one in both visual and physics + set_ignore_transform_notification(false); + + PhysicsServer::get_singleton()->body_static_simulate_motion(get_rid(),new_xform); //then simulate motion! + + setting=false; + pending=false; + +} + +void StaticBody::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + if (pre_xform) + *pre_xform = get_global_transform(); + pending=false; + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + if (simulating_motion && !pending && is_inside_scene() && !setting && !get_scene()->is_editor_hint()) { + + call_deferred(SceneStringNames::get_singleton()->_update_xform); + pending=true; + } + + } break; + } + + +} + +void StaticBody::set_simulate_motion(bool p_enable) { + + if (p_enable==simulating_motion) + return; + simulating_motion=p_enable; + + if (p_enable) { + pre_xform = memnew( Transform ); + if (is_inside_scene()) + *pre_xform=get_transform(); +// query = PhysicsServer::get_singleton()->query_create(this,"_state_notify",Variant()); + // PhysicsServer::get_singleton()->query_body_direct_state(query,get_rid()); + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_state_notify"); + + } else { + memdelete( pre_xform ); + pre_xform=NULL; + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),NULL,StringName()); + pending=false; + } +} + +bool StaticBody::is_simulating_motion() const { + + return simulating_motion; +} + +void StaticBody::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_simulate_motion","enabled"),&StaticBody::set_simulate_motion); + ObjectTypeDB::bind_method(_MD("is_simulating_motion"),&StaticBody::is_simulating_motion); + ObjectTypeDB::bind_method(_MD("_update_xform"),&StaticBody::_update_xform); + ObjectTypeDB::bind_method(_MD("_state_notify"),&StaticBody::_state_notify); + ObjectTypeDB::bind_method(_MD("set_constant_linear_velocity","vel"),&StaticBody::set_constant_linear_velocity); + ObjectTypeDB::bind_method(_MD("set_constant_angular_velocity","vel"),&StaticBody::set_constant_angular_velocity); + ObjectTypeDB::bind_method(_MD("get_constant_linear_velocity"),&StaticBody::get_constant_linear_velocity); + ObjectTypeDB::bind_method(_MD("get_constant_angular_velocity"),&StaticBody::get_constant_angular_velocity); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"simulate_motion"),_SCS("set_simulate_motion"),_SCS("is_simulating_motion")); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"constant_linear_velocity"),_SCS("set_constant_linear_velocity"),_SCS("get_constant_linear_velocity")); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"constant_angular_velocity"),_SCS("set_constant_angular_velocity"),_SCS("get_constant_angular_velocity")); +} + +StaticBody::StaticBody() : PhysicsBody(PhysicsServer::BODY_MODE_STATIC) { + + simulating_motion=false; + pre_xform=NULL; + setting=false; + pending=false; + //constant_angular_velocity=0; + +} + +StaticBody::~StaticBody() { + + if (pre_xform) + memdelete(pre_xform); + //if (query.is_valid()) + // PhysicsServer::get_singleton()->free(query); +} + + + + +void RigidBody::_body_enter_scene(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_FAIL_COND(!node); + + Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(E->get().in_scene); + + E->get().in_scene=true; + emit_signal(SceneStringNames::get_singleton()->body_enter,node); + + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->body_enter_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].local_shape); + } + +} + +void RigidBody::_body_exit_scene(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_FAIL_COND(!node); + Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(!E->get().in_scene); + E->get().in_scene=false; + emit_signal(SceneStringNames::get_singleton()->body_exit,node); + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].local_shape); + } +} + +void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape) { + + bool body_in = p_status==1; + ObjectID objid=p_instance; + + Object *obj = ObjectDB::get_instance(objid); + Node *node = obj ? obj->cast_to<Node>() : NULL; + + Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(objid); + + ERR_FAIL_COND(!body_in && !E); + + if (body_in) { + if (!E) { + + E = contact_monitor->body_map.insert(objid,BodyState()); + E->get().rc=0; + E->get().in_scene=node && node->is_inside_scene(); + if (node) { + node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid)); + if (E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_enter,node); + } + } + + } + E->get().rc++; + if (node) + E->get().shapes.insert(ShapePair(p_body_shape,p_local_shape)); + + + if (E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_enter_shape,objid,node,p_body_shape,p_local_shape); + } + + } else { + + E->get().rc--; + + if (node) + E->get().shapes.erase(ShapePair(p_body_shape,p_local_shape)); + + if (E->get().rc==0) { + + if (node) { + node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); + node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); + if (E->get().in_scene) + emit_signal(SceneStringNames::get_singleton()->body_exit,obj); + + } + + contact_monitor->body_map.erase(E); + } + if (node && E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_local_shape); + } + + } + +} + + +struct _RigidBodyInOut { + + ObjectID id; + int shape; + int local_shape; +}; + +void RigidBody::_direct_state_changed(Object *p_state) { + + //eh.. fuck +#ifdef DEBUG_ENABLED + + state=p_state->cast_to<PhysicsDirectBodyState>(); +#else + state=(PhysicsDirectBodyState*)p_state; //trust it +#endif + + if (contact_monitor) { + + //untag all + int rc=0; + for( Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) { + + for(int i=0;i<E->get().shapes.size();i++) { + + E->get().shapes[i].tagged=false; + rc++; + } + } + + _RigidBodyInOut *toadd=(_RigidBodyInOut*)alloca(state->get_contact_count()*sizeof(_RigidBodyInOut)); + int toadd_count=0;//state->get_contact_count(); + RigidBody_RemoveAction *toremove=(RigidBody_RemoveAction*)alloca(rc*sizeof(RigidBody_RemoveAction)); + int toremove_count=0; + + //put the ones to add + + for(int i=0;i<state->get_contact_count();i++) { + + ObjectID obj = state->get_contact_collider_id(i); + int local_shape = state->get_contact_local_shape(i); + int shape = state->get_contact_collider_shape(i); + toadd[i].local_shape=local_shape; + toadd[i].id=obj; + toadd[i].shape=shape; + + bool found=false; + + Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(obj); + if (!E) { + toadd_count++; + continue; + } + + ShapePair sp( shape,local_shape ); + int idx = E->get().shapes.find(sp); + if (idx==-1) { + + toadd_count++; + continue; + } + + E->get().shapes[idx].tagged=true; + } + + //put the ones to remove + + for( Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) { + + for(int i=0;i<E->get().shapes.size();i++) { + + if (!E->get().shapes[i].tagged) { + + toremove[toremove_count].body_id=E->key(); + toremove[toremove_count].pair=E->get().shapes[i]; + toremove_count++; + } + } + } + + + //process remotions + + for(int i=0;i<toremove_count;i++) { + + _body_inout(0,toremove[i].body_id,toremove[i].pair.body_shape,toremove[i].pair.local_shape); + } + + //process aditions + + for(int i=0;i<toadd_count;i++) { + + _body_inout(1,toadd[i].id,toadd[i].shape,toadd[i].local_shape); + } + + } + + set_ignore_transform_notification(true); + set_global_transform(state->get_transform()); + linear_velocity=state->get_linear_velocity(); + angular_velocity=state->get_angular_velocity(); + active=!state->is_sleeping(); + if (get_script_instance()) + get_script_instance()->call("_integrate_forces",state); + set_ignore_transform_notification(false); + + state=NULL; +} + +void RigidBody::_notification(int p_what) { + + +} + +void RigidBody::set_mode(Mode p_mode) { + + mode=p_mode; + switch(p_mode) { + + case MODE_RIGID: { + + PhysicsServer::get_singleton()->body_set_mode(get_rid(),PhysicsServer::BODY_MODE_RIGID); + } break; + case MODE_STATIC: { + + PhysicsServer::get_singleton()->body_set_mode(get_rid(),PhysicsServer::BODY_MODE_STATIC); + + } break; + case MODE_CHARACTER: { + PhysicsServer::get_singleton()->body_set_mode(get_rid(),PhysicsServer::BODY_MODE_CHARACTER); + + } break; + case MODE_STATIC_ACTIVE: { + + PhysicsServer::get_singleton()->body_set_mode(get_rid(),PhysicsServer::BODY_MODE_STATIC_ACTIVE); + } break; + + } +} + +RigidBody::Mode RigidBody::get_mode() const{ + + return mode; +} + +void RigidBody::set_mass(real_t p_mass){ + + ERR_FAIL_COND(p_mass<=0); + mass=p_mass; + _change_notify("mass"); + _change_notify("weight"); + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_MASS,mass); + +} +real_t RigidBody::get_mass() const{ + + return mass; +} + +void RigidBody::set_weight(real_t p_weight){ + + set_mass(p_weight/9.8); +} +real_t RigidBody::get_weight() const{ + + return mass*9.8; +} + + +void RigidBody::set_friction(real_t p_friction){ + + ERR_FAIL_COND(p_friction<0 || p_friction>1); + + friction=p_friction; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_FRICTION,friction); + +} +real_t RigidBody::get_friction() const{ + + return friction; +} + +void RigidBody::set_bounce(real_t p_bounce){ + + ERR_FAIL_COND(p_bounce<0 || p_bounce>1); + + bounce=p_bounce; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_BOUNCE,bounce); + +} +real_t RigidBody::get_bounce() const{ + + return bounce; +} + +void RigidBody::set_axis_velocity(const Vector3& p_axis) { + + Vector3 v = state? state->get_linear_velocity() : linear_velocity; + Vector3 axis = p_axis.normalized(); + v-=axis*axis.dot(v); + v+=p_axis; + if (state) { + set_linear_velocity(v); + } else { + PhysicsServer::get_singleton()->body_set_axis_velocity(get_rid(),p_axis); + linear_velocity=v; + } +} + +void RigidBody::set_linear_velocity(const Vector3& p_velocity){ + + linear_velocity=p_velocity; + if (state) + state->set_linear_velocity(linear_velocity); + else + PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_LINEAR_VELOCITY,linear_velocity); + +} + +Vector3 RigidBody::get_linear_velocity() const{ + + return linear_velocity; +} + +void RigidBody::set_angular_velocity(const Vector3& p_velocity){ + + angular_velocity=p_velocity; + if (state) + state->set_angular_velocity(angular_velocity); + else + PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_ANGULAR_VELOCITY,angular_velocity); +} +Vector3 RigidBody::get_angular_velocity() const{ + + return angular_velocity; +} + +void RigidBody::set_use_custom_integrator(bool p_enable){ + + if (custom_integrator==p_enable) + return; + + custom_integrator=p_enable; + PhysicsServer::get_singleton()->body_set_omit_force_integration(get_rid(),p_enable); + + +} +bool RigidBody::is_using_custom_integrator(){ + + return custom_integrator; +} + +void RigidBody::set_active(bool p_active) { + + active=p_active; + PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_SLEEPING,!active); + +} + +void RigidBody::set_can_sleep(bool p_active) { + + can_sleep=p_active; + PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_CAN_SLEEP,p_active); +} + +bool RigidBody::is_able_to_sleep() const { + + return can_sleep; +} + +bool RigidBody::is_active() const { + + return active; +} + +void RigidBody::set_max_contacts_reported(int p_amount) { + + max_contacts_reported=p_amount; + PhysicsServer::get_singleton()->body_set_max_contacts_reported(get_rid(),p_amount); +} + +int RigidBody::get_max_contacts_reported() const{ + + return max_contacts_reported; +} + +void RigidBody::apply_impulse(const Vector3& p_pos, const Vector3& p_impulse) { + + PhysicsServer::get_singleton()->body_apply_impulse(get_rid(),p_pos,p_impulse); +} + +void RigidBody::set_use_continuous_collision_detection(bool p_enable) { + + ccd=p_enable; + PhysicsServer::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(),p_enable); +} + +bool RigidBody::is_using_continuous_collision_detection() const { + + + return ccd; +} + + +void RigidBody::set_contact_monitor(bool p_enabled) { + + if (p_enabled==is_contact_monitor_enabled()) + return; + + if (!p_enabled) { + + for(Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) { + + //clean up mess + } + + memdelete( contact_monitor ); + contact_monitor=NULL; + } else { + + contact_monitor = memnew( ContactMonitor ); + } + +} + +bool RigidBody::is_contact_monitor_enabled() const { + + return contact_monitor!=NULL; +} + + + +void RigidBody::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_mode","mode"),&RigidBody::set_mode); + ObjectTypeDB::bind_method(_MD("get_mode"),&RigidBody::get_mode); + + ObjectTypeDB::bind_method(_MD("set_mass","mass"),&RigidBody::set_mass); + ObjectTypeDB::bind_method(_MD("get_mass"),&RigidBody::get_mass); + + ObjectTypeDB::bind_method(_MD("set_weight","weight"),&RigidBody::set_weight); + ObjectTypeDB::bind_method(_MD("get_weight"),&RigidBody::get_weight); + + ObjectTypeDB::bind_method(_MD("set_friction","friction"),&RigidBody::set_friction); + ObjectTypeDB::bind_method(_MD("get_friction"),&RigidBody::get_friction); + + ObjectTypeDB::bind_method(_MD("set_bounce","bounce"),&RigidBody::set_bounce); + ObjectTypeDB::bind_method(_MD("get_bounce"),&RigidBody::get_bounce); + + ObjectTypeDB::bind_method(_MD("set_linear_velocity","linear_velocity"),&RigidBody::set_linear_velocity); + ObjectTypeDB::bind_method(_MD("get_linear_velocity"),&RigidBody::get_linear_velocity); + + ObjectTypeDB::bind_method(_MD("set_angular_velocity","angular_velocity"),&RigidBody::set_angular_velocity); + ObjectTypeDB::bind_method(_MD("get_angular_velocity"),&RigidBody::get_angular_velocity); + + ObjectTypeDB::bind_method(_MD("set_max_contacts_reported","amount"),&RigidBody::set_max_contacts_reported); + ObjectTypeDB::bind_method(_MD("get_max_contacts_reported"),&RigidBody::get_max_contacts_reported); + + ObjectTypeDB::bind_method(_MD("set_use_custom_integrator","enable"),&RigidBody::set_use_custom_integrator); + ObjectTypeDB::bind_method(_MD("is_using_custom_integrator"),&RigidBody::is_using_custom_integrator); + + ObjectTypeDB::bind_method(_MD("set_contact_monitor","enabled"),&RigidBody::set_contact_monitor); + ObjectTypeDB::bind_method(_MD("is_contact_monitor_enabled"),&RigidBody::is_contact_monitor_enabled); + + ObjectTypeDB::bind_method(_MD("set_use_continuous_collision_detection","enable"),&RigidBody::set_use_continuous_collision_detection); + ObjectTypeDB::bind_method(_MD("is_using_continuous_collision_detection"),&RigidBody::is_using_continuous_collision_detection); + + ObjectTypeDB::bind_method(_MD("set_axis_velocity","axis_velocity"),&RigidBody::set_axis_velocity); + ObjectTypeDB::bind_method(_MD("apply_impulse","pos","impulse"),&RigidBody::apply_impulse); + + ObjectTypeDB::bind_method(_MD("set_active","active"),&RigidBody::set_active); + ObjectTypeDB::bind_method(_MD("is_active"),&RigidBody::is_active); + + ObjectTypeDB::bind_method(_MD("set_can_sleep","able_to_sleep"),&RigidBody::set_can_sleep); + ObjectTypeDB::bind_method(_MD("is_able_to_sleep"),&RigidBody::is_able_to_sleep); + + ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&RigidBody::_direct_state_changed); + ObjectTypeDB::bind_method(_MD("_body_enter_scene"),&RigidBody::_body_enter_scene); + ObjectTypeDB::bind_method(_MD("_body_exit_scene"),&RigidBody::_body_exit_scene); + + BIND_VMETHOD(MethodInfo("_integrate_forces",PropertyInfo(Variant::OBJECT,"state:PhysicsDirectBodyState"))); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Rigid,Static,Character,Static Active"),_SCS("set_mode"),_SCS("get_mode")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"mass",PROPERTY_HINT_EXP_RANGE,"0.01,65535,0.01"),_SCS("set_mass"),_SCS("get_mass")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"weight",PROPERTY_HINT_EXP_RANGE,"0.01,65535,0.01",PROPERTY_USAGE_EDITOR),_SCS("set_weight"),_SCS("get_weight")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_friction"),_SCS("get_friction")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_bounce"),_SCS("get_bounce")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"custom_integrator"),_SCS("set_use_custom_integrator"),_SCS("is_using_custom_integrator")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"continuous_cd"),_SCS("set_use_continuous_collision_detection"),_SCS("is_using_continuous_collision_detection")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"contacts_reported"),_SCS("set_max_contacts_reported"),_SCS("get_max_contacts_reported")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"contact_monitor"),_SCS("set_contact_monitor"),_SCS("is_contact_monitor_enabled")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"active"),_SCS("set_active"),_SCS("is_active")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"can_sleep"),_SCS("set_can_sleep"),_SCS("is_able_to_sleep")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"velocity/linear"),_SCS("set_linear_velocity"),_SCS("get_linear_velocity")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"velocity/angular"),_SCS("set_angular_velocity"),_SCS("get_angular_velocity")); + + ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape"))); + ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape"))); + ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body"))); + ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body"))); + + BIND_CONSTANT( MODE_STATIC ); + BIND_CONSTANT( MODE_STATIC_ACTIVE ); + BIND_CONSTANT( MODE_RIGID ); + BIND_CONSTANT( MODE_CHARACTER ); +} + +RigidBody::RigidBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) { + + mode=MODE_RIGID; + + bounce=0; + mass=1; + friction=1; + max_contacts_reported=0; + state=NULL; + + //angular_velocity=0; + active=true; + ccd=false; + + custom_integrator=false; + contact_monitor=NULL; + can_sleep=true; + + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_direct_state_changed"); +} + +RigidBody::~RigidBody() { + + if (contact_monitor) + memdelete( contact_monitor ); + + + +} + diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h new file mode 100644 index 0000000000..0cb24075bd --- /dev/null +++ b/scene/3d/physics_body.h @@ -0,0 +1,219 @@ +/*************************************************************************/ +/* physics_body.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef PHYSICS_BODY__H +#define PHYSICS_BODY__H + +#include "scene/3d/collision_object.h" +#include "servers/physics_server.h" +#include "vset.h" + + +class PhysicsBody : public CollisionObject { + + OBJ_TYPE(PhysicsBody,CollisionObject); + +protected: + + void _notification(int p_what); + PhysicsBody(PhysicsServer::BodyMode p_mode); +public: + + PhysicsBody(); + +}; + +class StaticBody : public PhysicsBody { + + OBJ_TYPE(StaticBody,PhysicsBody); + + Transform *pre_xform; + //RID query; + bool setting; + bool pending; + bool simulating_motion; + Vector3 constant_linear_velocity; + Vector3 constant_angular_velocity; + void _update_xform(); + void _state_notify(Object *p_object); + +protected: + + void _notification(int p_what); + static void _bind_methods(); + +public: + + void set_simulate_motion(bool p_enable); + bool is_simulating_motion() const; + + void set_constant_linear_velocity(const Vector3& p_vel); + void set_constant_angular_velocity(const Vector3& p_vel); + + Vector3 get_constant_linear_velocity() const; + Vector3 get_constant_angular_velocity() const; + + StaticBody(); + ~StaticBody(); + +}; + +class RigidBody : public PhysicsBody { + + OBJ_TYPE(RigidBody,PhysicsBody); +public: + + enum Mode { + MODE_RIGID, + MODE_STATIC, + MODE_CHARACTER, + MODE_STATIC_ACTIVE, + }; +private: + + bool can_sleep; + PhysicsDirectBodyState *state; + Mode mode; + + real_t bounce; + real_t mass; + real_t friction; + + Vector3 linear_velocity; + Vector3 angular_velocity; + bool active; + bool ccd; + + + int max_contacts_reported; + + bool custom_integrator; + + + struct ShapePair { + + int body_shape; + int local_shape; + bool tagged; + bool operator<(const ShapePair& p_sp) const { + if (body_shape==p_sp.body_shape) + return local_shape < p_sp.local_shape; + else + return body_shape < p_sp.body_shape; + } + + ShapePair() {} + ShapePair(int p_bs, int p_ls) { body_shape=p_bs; local_shape=p_ls; } + }; + struct RigidBody_RemoveAction { + + + ObjectID body_id; + ShapePair pair; + + }; + struct BodyState { + + int rc; + bool in_scene; + VSet<ShapePair> shapes; + }; + + struct ContactMonitor { + + + Map<ObjectID,BodyState> body_map; + + }; + + + ContactMonitor *contact_monitor; + void _body_enter_scene(ObjectID p_id); + void _body_exit_scene(ObjectID p_id); + + + void _body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape); + void _direct_state_changed(Object *p_state); + + +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_mode(Mode p_mode); + Mode get_mode() const; + + void set_mass(real_t p_mass); + real_t get_mass() const; + + void set_weight(real_t p_weight); + real_t get_weight() const; + + void set_friction(real_t p_friction); + real_t get_friction() const; + + void set_bounce(real_t p_bounce); + real_t get_bounce() const; + + void set_linear_velocity(const Vector3& p_velocity); + Vector3 get_linear_velocity() const; + + void set_axis_velocity(const Vector3& p_axis); + + void set_angular_velocity(const Vector3&p_velocity); + Vector3 get_angular_velocity() const; + + void set_use_custom_integrator(bool p_enable); + bool is_using_custom_integrator(); + + void set_active(bool p_active); + bool is_active() const; + + void set_can_sleep(bool p_active); + bool is_able_to_sleep() const; + + void set_contact_monitor(bool p_enabled); + bool is_contact_monitor_enabled() const; + + void set_max_contacts_reported(int p_amount); + int get_max_contacts_reported() const; + + void set_use_continuous_collision_detection(bool p_enable); + bool is_using_continuous_collision_detection() const; + + void apply_impulse(const Vector3& p_pos, const Vector3& p_impulse); + + RigidBody(); + ~RigidBody(); + +}; + +VARIANT_ENUM_CAST(RigidBody::Mode); +#endif // PHYSICS_BODY__H diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp new file mode 100644 index 0000000000..961198c8d4 --- /dev/null +++ b/scene/3d/physics_joint.cpp @@ -0,0 +1,327 @@ +/*************************************************************************/ +/* physics_joint.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "physics_joint.h" + +#if 0 + +void PhysicsJoint::_set(const String& p_name, const Variant& p_value) { + + if (p_name=="body_A") + set_body_A(p_value); + else if (p_name=="body_B") + set_body_B(p_value); + else if (p_name=="active") + set_active(p_value); + else if (p_name=="no_collision") + set_disable_collision(p_value); +} +Variant PhysicsJoint::_get(const String& p_name) const { + + if (p_name=="body_A") + return get_body_A(); + else if (p_name=="body_B") + return get_body_B(); + else if (p_name=="active") + return is_active(); + else if (p_name=="no_collision") + return has_disable_collision(); + + return Variant(); +} +void PhysicsJoint::_get_property_list( List<PropertyInfo> *p_list) const { + + + p_list->push_back( PropertyInfo( Variant::NODE_PATH, "body_A" ) ); + p_list->push_back( PropertyInfo( Variant::NODE_PATH, "body_B" ) ); + p_list->push_back( PropertyInfo( Variant::BOOL, "active" ) ); + p_list->push_back( PropertyInfo( Variant::BOOL, "no_collision" ) ); +} +void PhysicsJoint::_notification(int p_what) { + + + switch(p_what) { + + case NOTIFICATION_PARENT_CONFIGURED: { + + _connect(); + if (get_root_node()->get_editor() && !indicator.is_valid()) { + + indicator=VisualServer::get_singleton()->poly_create(); + RID mat=VisualServer::get_singleton()->fixed_material_create(); + VisualServer::get_singleton()->material_set_flag( mat, VisualServer::MATERIAL_FLAG_UNSHADED, true ); + VisualServer::get_singleton()->material_set_flag( mat, VisualServer::MATERIAL_FLAG_ONTOP, true ); + VisualServer::get_singleton()->material_set_flag( mat, VisualServer::MATERIAL_FLAG_WIREFRAME, true ); + VisualServer::get_singleton()->material_set_flag( mat, VisualServer::MATERIAL_FLAG_DOUBLE_SIDED, true ); + VisualServer::get_singleton()->material_set_line_width( mat, 3 ); + + VisualServer::get_singleton()->poly_set_material(indicator,mat,true); + _update_indicator(); + + } + + if (indicator.is_valid()) { + + indicator_instance=VisualServer::get_singleton()->instance_create(indicator,get_world()->get_scenario()); + VisualServer::get_singleton()->instance_attach_object_instance_ID( indicator_instance,get_instance_ID() ); + } + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + if (indicator_instance.is_valid()) { + + VisualServer::get_singleton()->instance_set_transform(indicator_instance,get_global_transform()); + } + } break; + case NOTIFICATION_EXIT_SCENE: { + + if (indicator_instance.is_valid()) { + + VisualServer::get_singleton()->free(indicator_instance); + } + _disconnect(); + + } break; + + } +} + + +RID PhysicsJoint::_get_visual_instance_rid() const { + + return indicator_instance; + +} + +void PhysicsJoint::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_get_visual_instance_rid"),&PhysicsJoint::_get_visual_instance_rid); + ObjectTypeDB::bind_method(_MD("set_body_A","path"),&PhysicsJoint::set_body_A); + ObjectTypeDB::bind_method(_MD("set_body_B"),&PhysicsJoint::set_body_B); + ObjectTypeDB::bind_method(_MD("get_body_A","path"),&PhysicsJoint::get_body_A); + ObjectTypeDB::bind_method(_MD("get_body_B"),&PhysicsJoint::get_body_B); + + ObjectTypeDB::bind_method(_MD("set_active","active"),&PhysicsJoint::set_active); + ObjectTypeDB::bind_method(_MD("is_active"),&PhysicsJoint::is_active); + + ObjectTypeDB::bind_method(_MD("set_disable_collision","disable"),&PhysicsJoint::set_disable_collision); + ObjectTypeDB::bind_method(_MD("has_disable_collision"),&PhysicsJoint::has_disable_collision); + + + ObjectTypeDB::bind_method("reconnect",&PhysicsJoint::reconnect); + + ObjectTypeDB::bind_method(_MD("get_rid"),&PhysicsJoint::get_rid); + +} + +void PhysicsJoint::set_body_A(const NodePath& p_path) { + + _disconnect(); + body_A=p_path; + _connect(); + _change_notify("body_A"); +} +void PhysicsJoint::set_body_B(const NodePath& p_path) { + + _disconnect(); + body_B=p_path; + _connect(); + _change_notify("body_B"); + +} +NodePath PhysicsJoint::get_body_A() const { + + return body_A; +} +NodePath PhysicsJoint::get_body_B() const { + + return body_B; +} + +void PhysicsJoint::set_active(bool p_active) { + + active=p_active; + if (is_inside_scene()) { + PhysicsServer::get_singleton()->joint_set_active(joint,active); + } + _change_notify("active"); +} + +void PhysicsJoint::set_disable_collision(bool p_active) { + + if (no_collision==p_active) + return; + _disconnect(); + no_collision=p_active; + _connect(); + + _change_notify("no_collision"); +} +bool PhysicsJoint::has_disable_collision() const { + + return no_collision; +} + + + +bool PhysicsJoint::is_active() const { + + return active; +} + +void PhysicsJoint::_disconnect() { + + if (!is_inside_scene()) + return; + + if (joint.is_valid()) + PhysicsServer::get_singleton()->free(joint); + + joint=RID(); + + Node *nA = get_node(body_A); + Node *nB = get_node(body_B); + + PhysicsBody *A = nA?nA->cast_to<PhysicsBody>():NULL; + PhysicsBody *B = nA?nB->cast_to<PhysicsBody>():NULL; + + if (!A ||!B) + return; + + if (no_collision) + PhysicsServer::get_singleton()->body_remove_collision_exception(A->get_body(),B->get_body()); + +} +void PhysicsJoint::_connect() { + + if (!is_inside_scene()) + return; + + ERR_FAIL_COND(joint.is_valid()); + + Node *nA = get_node(body_A); + Node *nB = get_node(body_B); + + PhysicsBody *A = nA?nA->cast_to<PhysicsBody>():NULL; + PhysicsBody *B = nA?nB->cast_to<PhysicsBody>():NULL; + + if (!A && !B) + return; + + if (B && !A) + SWAP(B,A); + + joint = create(A,B); + + if (A<B) + SWAP(A,B); + + if (no_collision) + PhysicsServer::get_singleton()->body_add_collision_exception(A->get_body(),B->get_body()); + + + +} + +void PhysicsJoint::reconnect() { + + _disconnect(); + _connect(); + +} + + +RID PhysicsJoint::get_rid() { + + return joint; +} + + +PhysicsJoint::PhysicsJoint() { + + active=true; + no_collision=true; +} + + +PhysicsJoint::~PhysicsJoint() { + + if (indicator.is_valid()) { + + VisualServer::get_singleton()->free(indicator); + } + +} + +/* PIN */ + +void PhysicsJointPin::_update_indicator() { + + + VisualServer::get_singleton()->poly_clear(indicator); + + Vector<Color> colors; + colors.push_back( Color(0.3,0.9,0.2,0.7) ); + colors.push_back( Color(0.3,0.9,0.2,0.7) ); + + Vector<Vector3> points; + points.resize(2); + points[0]=Vector3(Vector3(-0.2,0,0)); + points[1]=Vector3(Vector3(0.2,0,0)); + VisualServer::get_singleton()->poly_add_primitive(indicator,points,Vector<Vector3>(),colors,Vector<Vector3>()); + + points[0]=Vector3(Vector3(0,-0.2,0)); + points[1]=Vector3(Vector3(0,0.2,0)); + VisualServer::get_singleton()->poly_add_primitive(indicator,points,Vector<Vector3>(),colors,Vector<Vector3>()); + + points[0]=Vector3(Vector3(0,0,-0.2)); + points[1]=Vector3(Vector3(0,0,0.2)); + VisualServer::get_singleton()->poly_add_primitive(indicator,points,Vector<Vector3>(),colors,Vector<Vector3>()); + +} + +RID PhysicsJointPin::create(PhysicsBody*A,PhysicsBody*B) { + + RID body_A = A->get_body(); + RID body_B = B?B->get_body():RID(); + + ERR_FAIL_COND_V( !body_A.is_valid(), RID() ); + + Vector3 pin_pos = get_global_transform().origin; + + if (body_B.is_valid()) + return PhysicsServer::get_singleton()->joint_create_double_pin_global(body_A,pin_pos,body_B,pin_pos); + else + return PhysicsServer::get_singleton()->joint_create_pin(body_A,A->get_global_transform().xform_inv(pin_pos),pin_pos); +} + +PhysicsJointPin::PhysicsJointPin() { + + +} +#endif diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h new file mode 100644 index 0000000000..4a0c609e69 --- /dev/null +++ b/scene/3d/physics_joint.h @@ -0,0 +1,104 @@ +/*************************************************************************/ +/* physics_joint.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef PHYSICS_JOINT_H +#define PHYSICS_JOINT_H + +#include "scene/3d/spatial.h" +#include "scene/3d/physics_body.h" + +#if 0 +class PhysicsJoint : public Spatial { + + OBJ_TYPE(PhysicsJoint,Spatial); + OBJ_CATEGORY("3D Physics Nodes"); + + NodePath body_A; + NodePath body_B; + bool active; + bool no_collision; + + + RID indicator_instance; + + RID _get_visual_instance_rid() const; +protected: + + RID joint; + RID indicator; + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + void _notification(int p_what); + static void _bind_methods(); + + virtual RID create(PhysicsBody*A,PhysicsBody*B)=0; + virtual void _update_indicator()=0; + + void _disconnect(); + void _connect(); +public: + + void set_body_A(const NodePath& p_path); + void set_body_B(const NodePath& p_path); + NodePath get_body_A() const; + NodePath get_body_B() const; + + void set_active(bool p_active); + bool is_active() const; + + void set_disable_collision(bool p_active); + bool has_disable_collision() const; + + void reconnect(); + + RID get_rid(); + + PhysicsJoint(); + ~PhysicsJoint(); +}; + + + +class PhysicsJointPin : public PhysicsJoint { + + OBJ_TYPE( PhysicsJointPin, PhysicsJoint ); + +protected: + + virtual void _update_indicator(); + virtual RID create(PhysicsBody*A,PhysicsBody*B); +public: + + + PhysicsJointPin(); +}; + +#endif // PHYSICS_JOINT_H +#endif diff --git a/scene/3d/portal.cpp b/scene/3d/portal.cpp new file mode 100644 index 0000000000..12b9dc4b7a --- /dev/null +++ b/scene/3d/portal.cpp @@ -0,0 +1,281 @@ +/*************************************************************************/ +/* portal.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "portal.h" +#include "servers/visual_server.h" +#include "scene/resources/surface_tool.h" +#include "globals.h" + +bool Portal::_set(const StringName& p_name, const Variant& p_value) { + + if (p_name=="shape") { + DVector<float> src_coords=p_value; + Vector<Point2> points; + int src_coords_size = src_coords.size(); + ERR_FAIL_COND_V(src_coords_size%2,false); + points.resize(src_coords_size/2); + for (int i=0;i<points.size();i++) { + + points[i].x=src_coords[i*2+0]; + points[i].y=src_coords[i*2+1]; + set_shape(points); + } + } else if (p_name=="enabled") { + set_enabled(p_value); + } else if (p_name=="disable_distance") { + set_disable_distance(p_value); + } else if (p_name=="disabled_color") { + set_disabled_color(p_value); + } else if (p_name=="connect_range") { + set_connect_range(p_value); + } else + return false; + + return true; +} + +bool Portal::_get(const StringName& p_name,Variant &r_ret) const { + + if (p_name=="shape") { + Vector<Point2> points=get_shape(); + DVector<float> dst_coords; + dst_coords.resize(points.size()*2); + + for (int i=0;i<points.size();i++) { + + dst_coords.set(i*2+0,points[i].x); + dst_coords.set(i*2+1,points[i].y); + } + + r_ret= dst_coords; + } else if (p_name=="enabled") { + r_ret= is_enabled(); + } else if (p_name=="disable_distance") { + r_ret= get_disable_distance(); + } else if (p_name=="disabled_color") { + r_ret= get_disabled_color(); + } else if (p_name=="connect_range") { + r_ret= get_connect_range(); + } else + return false; + return true; +} + +void Portal::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo( Variant::REAL_ARRAY, "shape" ) ); + p_list->push_back( PropertyInfo( Variant::BOOL, "enabled" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "disable_distance",PROPERTY_HINT_RANGE,"0,4096,0.01" ) ); + p_list->push_back( PropertyInfo( Variant::COLOR, "disabled_color") ); + p_list->push_back( PropertyInfo( Variant::REAL, "connect_range",PROPERTY_HINT_RANGE,"0.1,4096,0.01" ) ); +} + + +RES Portal::_get_gizmo_geometry() const { + + Ref<SurfaceTool> surface_tool( memnew( SurfaceTool )); + + Ref<FixedMaterial> mat( memnew( FixedMaterial )); + + mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(1.0,0.8,0.8,0.7) ); + mat->set_line_width(4); + mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); + mat->set_flag(Material::FLAG_UNSHADED,true); + mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true); + + surface_tool->begin(Mesh::PRIMITIVE_LINES); + surface_tool->set_material(mat); + + Vector<Point2> shape = get_shape(); + + Vector2 center; + for (int i=0;i<shape.size();i++) { + + int n=(i+1)%shape.size(); + Vector<Vector3> points; + surface_tool->add_vertex( Vector3( shape[i].x, shape[i].y,0 )); + surface_tool->add_vertex( Vector3( shape[n].x, shape[n].y,0 )); + center+=shape[i]; + + } + + if (shape.size()>0) { + + center/=shape.size(); + Vector<Vector3> points; + surface_tool->add_vertex( Vector3( center.x, center.y,0 )); + surface_tool->add_vertex( Vector3( center.x, center.y,1.0 )); + } + + return surface_tool->commit(); +} + + + +AABB Portal::get_aabb() const { + + return aabb; +} +DVector<Face3> Portal::get_faces(uint32_t p_usage_flags) const { + + if (!(p_usage_flags&FACES_ENCLOSING)) + return DVector<Face3>(); + + Vector<Point2> shape = get_shape(); + if (shape.size()==0) + return DVector<Face3>(); + + Vector2 center; + for (int i=0;i<shape.size();i++) { + + center+=shape[i]; + + } + + DVector<Face3> ret; + center/=shape.size(); + + for (int i=0;i<shape.size();i++) { + + int n=(i+1)%shape.size(); + + Face3 f; + f.vertex[0]=Vector3( center.x, center.y, 0 ); + f.vertex[1]=Vector3( shape[i].x, shape[i].y, 0 ); + f.vertex[2]=Vector3( shape[n].x, shape[n].y, 0 ); + ret.push_back(f); + } + + return ret; +} + +void Portal::set_shape(const Vector<Point2>& p_shape) { + + + VisualServer::get_singleton()->portal_set_shape(portal, p_shape); + update_gizmo(); +} + +Vector<Point2> Portal::get_shape() const { + + return VisualServer::get_singleton()->portal_get_shape(portal); +} + +void Portal::set_connect_range(float p_range) { + + connect_range=p_range; + VisualServer::get_singleton()->portal_set_connect_range(portal,p_range); +} + +float Portal::get_connect_range() const { + + return connect_range; +} + + +void Portal::set_enabled(bool p_enabled) { + + enabled=p_enabled; + VisualServer::get_singleton()->portal_set_enabled(portal,enabled); +} + +bool Portal::is_enabled() const { + + + return enabled; +} + +void Portal::set_disable_distance(float p_distance) { + + disable_distance=p_distance; + VisualServer::get_singleton()->portal_set_disable_distance(portal,disable_distance); + +} +float Portal::get_disable_distance() const { + + + return disable_distance; +} + +void Portal::set_disabled_color(const Color& p_disabled_color) { + + disabled_color=p_disabled_color; + VisualServer::get_singleton()->portal_set_disabled_color(portal,disabled_color); +} + +Color Portal::get_disabled_color() const { + + return disabled_color; +} + +void Portal::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_shape","points"),&Portal::set_shape); + ObjectTypeDB::bind_method(_MD("get_shape"),&Portal::get_shape); + + ObjectTypeDB::bind_method(_MD("set_enabled","enable"),&Portal::set_enabled); + ObjectTypeDB::bind_method(_MD("is_enabled"),&Portal::is_enabled); + + ObjectTypeDB::bind_method(_MD("set_disable_distance","distance"),&Portal::set_disable_distance); + ObjectTypeDB::bind_method(_MD("get_disable_distance"),&Portal::get_disable_distance); + + ObjectTypeDB::bind_method(_MD("set_disabled_color","color"),&Portal::set_disabled_color); + ObjectTypeDB::bind_method(_MD("get_disabled_color"),&Portal::get_disabled_color); + + ObjectTypeDB::bind_method(_MD("set_connect_range","range"),&Portal::set_connect_range); + ObjectTypeDB::bind_method(_MD("get_connect_range"),&Portal::get_connect_range); + +} + +Portal::Portal() { + + portal = VisualServer::get_singleton()->portal_create(); + Vector< Point2 > points; + points.push_back( Point2( -1, 1 ) ); + points.push_back( Point2( 1, 1 ) ); + points.push_back( Point2( 1, -1 ) ); + points.push_back( Point2( -1, -1 ) ); + set_shape(points); // default shape + + + set_connect_range(0.8); + set_disable_distance(50); + set_enabled(true); + + set_base(portal); + + +} + + +Portal::~Portal() { + + VisualServer::get_singleton()->free(portal); +} + + diff --git a/scene/3d/portal.h b/scene/3d/portal.h new file mode 100644 index 0000000000..6905724499 --- /dev/null +++ b/scene/3d/portal.h @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* portal.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef PORTAL_H +#define PORTAL_H + +#include "scene/3d/visual_instance.h" +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + + +/* Portal Logic: + If a portal is placed next (very close to) a similar, opposing portal, they automatically connect, + otherwise, a portal connects to the parent room +*/ + + + +class Portal : public VisualInstance { + + OBJ_TYPE(Portal, VisualInstance); + + RID portal; + + bool enabled; + float disable_distance; + Color disabled_color; + float connect_range; + + AABB aabb; + + virtual RES _get_gizmo_geometry() const; + +protected: + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + + static void _bind_methods(); + +public: + + virtual AABB get_aabb() const; + virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; + + void set_enabled(bool p_enabled); + bool is_enabled() const; + + void set_disable_distance(float p_distance); + float get_disable_distance() const; + + void set_disabled_color(const Color& p_disabled_color); + Color get_disabled_color() const; + + void set_shape(const Vector<Point2>& p_shape); + Vector<Point2> get_shape() const; + + void set_connect_range(float p_range); + float get_connect_range() const; + + Portal(); + ~Portal(); + +}; + +#endif diff --git a/scene/3d/position_3d.cpp b/scene/3d/position_3d.cpp new file mode 100644 index 0000000000..19bf1c4e1d --- /dev/null +++ b/scene/3d/position_3d.cpp @@ -0,0 +1,66 @@ +/*************************************************************************/ +/* position_3d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "position_3d.h" +#include "scene/resources/mesh.h" + +RES Position3D::_get_gizmo_geometry() const { + + + Ref<Mesh> mesh = memnew( Mesh ); + + DVector<Vector3> cursor_points; + DVector<Color> cursor_colors; + float cs = 0.25; + cursor_points.push_back(Vector3(+cs,0,0)); + cursor_points.push_back(Vector3(-cs,0,0)); + cursor_points.push_back(Vector3(0,+cs,0)); + cursor_points.push_back(Vector3(0,-cs,0)); + cursor_points.push_back(Vector3(0,0,+cs)); + cursor_points.push_back(Vector3(0,0,-cs)); + cursor_colors.push_back(Color(1,0.5,0.5,1)); + cursor_colors.push_back(Color(1,0.5,0.5,1)); + cursor_colors.push_back(Color(0.5,1,0.5,1)); + cursor_colors.push_back(Color(0.5,1,0.5,1)); + cursor_colors.push_back(Color(0.5,0.5,1,1)); + cursor_colors.push_back(Color(0.5,0.5,1,1)); + + Ref<FixedMaterial> mat = memnew( FixedMaterial ); + mat->set_flag(Material::FLAG_UNSHADED,true); + mat->set_line_width(3); + Array d; + d[Mesh::ARRAY_VERTEX]=cursor_points; + d[Mesh::ARRAY_COLOR]=cursor_colors; + mesh->add_surface(Mesh::PRIMITIVE_LINES,d); + mesh->surface_set_material(0,mat); + return mesh; +} + +Position3D::Position3D() +{ +} diff --git a/scene/3d/position_3d.h b/scene/3d/position_3d.h new file mode 100644 index 0000000000..468b9aafeb --- /dev/null +++ b/scene/3d/position_3d.h @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* position_3d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef POSITION_3D_H +#define POSITION_3D_H + +#include "scene/3d/spatial.h" + +class Position3D : public Spatial { + + OBJ_TYPE(Position3D,Spatial); + + virtual RES _get_gizmo_geometry() const; + +public: + + Position3D(); +}; + +#endif // POSITION_3D_H diff --git a/scene/3d/proximity_group.cpp b/scene/3d/proximity_group.cpp new file mode 100644 index 0000000000..b3378c7698 --- /dev/null +++ b/scene/3d/proximity_group.cpp @@ -0,0 +1,198 @@ +/*************************************************************************/ +/* proximity_group.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "proximity_group.h" + +#include "math_funcs.h" + +void ProximityGroup::clear_groups() { + + Map<StringName, uint32_t>::Element *E; + + { + const int size = 16; + StringName remove_list[size]; + E = groups.front(); + int num = 0; + while (E && num < size) { + + if (E->get() != group_version) { + remove_list[num++] = E->key(); + }; + + E = E->next(); + }; + for (int i=0; i<num; i++) { + + groups.erase(remove_list[i]); + }; + }; + + if (E) { + clear_groups(); // call until we go through the whole list + }; +}; + +void ProximityGroup::update_groups() { + + if (grid_radius == Vector3(0, 0, 0)) + return; + + ++group_version; + + Vector3 pos = get_global_transform().get_origin(); + Vector3 vcell = pos / cell_size; + int cell[3] = { Math::fast_ftoi(vcell.x), Math::fast_ftoi(vcell.y), Math::fast_ftoi(vcell.z) }; + + add_groups(cell, group_name, 0); + + clear_groups(); +}; + +void ProximityGroup::add_groups(int* p_cell, String p_base, int p_depth) { + + p_base = p_base + "|"; + if (grid_radius[p_depth] == 0) { + + if (p_depth == 2) { + _new_group(p_base); + } else { + add_groups(p_cell, p_base, p_depth + 1); + }; + }; + + int start = p_cell[p_depth] - grid_radius[p_depth]; + int end = p_cell[p_depth] + grid_radius[p_depth]; + + for (int i=start; i<=end; i++) { + + String gname = p_base + itos(i); + if (p_depth == 2) { + _new_group(gname); + } else { + add_groups(p_cell, gname, p_depth + 1); + }; + }; +}; + +void ProximityGroup::_new_group(StringName p_name) { + + const Map<StringName, uint32_t>::Element* E = groups.find(p_name); + if (!E) { + add_to_group(p_name); + }; + + groups[p_name] = group_version; +}; + +void ProximityGroup::set_group_name(String p_group_name) { + + group_name = p_group_name; +}; + +void ProximityGroup::_notification(int what) { + + switch (what) { + + case NOTIFICATION_EXIT_SCENE: + ++group_version; + clear_groups(); + break; + case NOTIFICATION_TRANSFORM_CHANGED: + update_groups(); + break; + }; +}; + +void ProximityGroup::broadcast(String p_name, Variant p_params) { + + Map<StringName, uint32_t>::Element *E; + E = groups.front(); + while (E) { + + get_scene()->call_group(SceneMainLoop::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_name, p_params); + E = E->next(); + }; + +}; + +void ProximityGroup::_proximity_group_broadcast(String p_name, Variant p_params) { + + if (dispatch_mode == MODE_PROXY) { + + get_parent()->call(p_name, p_params); + } else { + + emit_signal("broadcast", p_name, p_params); + }; +}; + + +void ProximityGroup::set_dispatch_mode(int p_mode) { + + dispatch_mode = (DispatchMode)p_mode; +}; + +void ProximityGroup::set_grid_radius(const Vector3& p_radius) { + + grid_radius = p_radius; +}; + +Vector3 ProximityGroup::get_grid_radius() const { + + return grid_radius; +}; + + +void ProximityGroup::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_group_name","name"), &ProximityGroup::set_group_name); + ObjectTypeDB::bind_method(_MD("broadcast","name", "parameters"), &ProximityGroup::broadcast); + ObjectTypeDB::bind_method(_MD("set_dispatch_mode","mode"), &ProximityGroup::set_dispatch_mode); + ObjectTypeDB::bind_method(_MD("_proximity_group_broadcast","name","params"), &ProximityGroup::_proximity_group_broadcast); + ObjectTypeDB::bind_method(_MD("set_grid_radius","radius"), &ProximityGroup::set_grid_radius); + ObjectTypeDB::bind_method(_MD("get_grid_radius"), &ProximityGroup::get_grid_radius); + + ADD_PROPERTY( PropertyInfo( Variant::VECTOR3, "grid_radius"), _SCS("set_grid_radius"), _SCS("get_grid_radius")); + + ADD_SIGNAL( MethodInfo("broadcast", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::ARRAY, "parameters")) ); +}; + + +ProximityGroup::ProximityGroup() { + + group_version = 0; + dispatch_mode = MODE_PROXY; + + grid_radius = Vector3(1, 1, 1); + +}; + +ProximityGroup::~ProximityGroup() { + +}; diff --git a/scene/3d/proximity_group.h b/scene/3d/proximity_group.h new file mode 100644 index 0000000000..c8660c17dd --- /dev/null +++ b/scene/3d/proximity_group.h @@ -0,0 +1,81 @@ +/*************************************************************************/ +/* proximity_group.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef PROXIMITY_GROUP_H +#define PROXIMITY_GROUP_H + +#include "spatial.h" + +class ProximityGroup : public Spatial { + + OBJ_TYPE( ProximityGroup, Spatial ); + OBJ_CATEGORY("3D"); + +public: + enum DispatchMode { + MODE_PROXY, + MODE_SIGNAL, + }; + +public: + void clear_groups(); + void update_groups(); + + void _notification(int p_what); + + DispatchMode dispatch_mode; + + Map<StringName, uint32_t> groups; + String group_name; + + float cell_size; + Vector3 grid_radius; + uint32_t group_version; + + void add_groups(int* p_cell, String p_base, int p_depth); + void _new_group(StringName p_name); + + void _proximity_group_broadcast(String p_name, Variant p_params); + + static void _bind_methods(); + +public: + + void set_group_name(String p_group_name); + void broadcast(String p_name, Variant p_params); + void set_dispatch_mode(int p_mode); + + void set_grid_radius(const Vector3& p_radius); + Vector3 get_grid_radius() const; + + ProximityGroup(); + ~ProximityGroup(); +}; + +#endif + diff --git a/scene/3d/quad.cpp b/scene/3d/quad.cpp new file mode 100644 index 0000000000..78dd56141c --- /dev/null +++ b/scene/3d/quad.cpp @@ -0,0 +1,232 @@ +/*************************************************************************/ +/* quad.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "quad.h" +#include "servers/visual_server.h" + +void Quad::_update() { + + if (!is_inside_scene()) + return; + + Vector3 normal; + normal[axis]=1.0; + + const int axis_order_1[3]={1,2,0}; + const int axis_order_2[3]={2,0,1}; + const int a1=axis_order_1[axis]; + const int a2=axis_order_2[axis]; + + + + DVector<Vector3> points; + points.resize(4); + DVector<Vector3>::Write pointsw = points.write(); + + Vector2 s2 = size*0.5; + Vector2 o = offset; + if (!centered) + o+=s2; + + pointsw[0][a1]=-s2.x+offset.x; + pointsw[0][a2]=s2.y+offset.y; + + pointsw[1][a1]=s2.x+offset.x; + pointsw[1][a2]=s2.y+offset.y; + + pointsw[2][a1]=s2.x+offset.x; + pointsw[2][a2]=-s2.y+offset.y; + + pointsw[3][a1]=-s2.x+offset.x; + pointsw[3][a2]=-s2.y+offset.y; + + + aabb=AABB(pointsw[0],Vector3()); + for(int i=1;i<4;i++) + aabb.expand_to(pointsw[i]); + + pointsw = DVector<Vector3>::Write(); + + DVector<Vector3> normals; + normals.resize(4); + DVector<Vector3>::Write normalsw = normals.write(); + + for(int i=0;i<4;i++) + normalsw[i]=normal; + + normalsw=DVector<Vector3>::Write(); + + + + DVector<Vector2> uvs; + uvs.resize(4); + DVector<Vector2>::Write uvsw = uvs.write(); + + uvsw[0]=Vector2(0,0); + uvsw[1]=Vector2(1,0); + uvsw[2]=Vector2(1,1); + uvsw[3]=Vector2(0,1); + + uvsw = DVector<Vector2>::Write(); + + DVector<int> indices; + indices.resize(6); + + DVector<int>::Write indicesw = indices.write(); + indicesw[0]=0; + indicesw[1]=1; + indicesw[2]=2; + indicesw[3]=2; + indicesw[4]=3; + indicesw[5]=0; + + indicesw=DVector<int>::Write(); + + Array arr; + arr.resize(VS::ARRAY_MAX); + arr[VS::ARRAY_VERTEX]=points; + arr[VS::ARRAY_NORMAL]=normals; + arr[VS::ARRAY_TEX_UV]=uvs; + arr[VS::ARRAY_INDEX]=indices; + + + if (configured) { + VS::get_singleton()->mesh_remove_surface(mesh,0); + } else { + configured=true; + } + VS::get_singleton()->mesh_add_surface(mesh,VS::PRIMITIVE_TRIANGLES,arr); + + pending_update=false; +} + + +void Quad::set_axis(Vector3::Axis p_axis) { + + axis=p_axis; + _update(); +} + +Vector3::Axis Quad::get_axis() const{ + + return axis; +} + +void Quad::set_size(const Vector2& p_size){ + + size=p_size; + _update(); +} +Vector2 Quad::get_size() const{ + + return size; +} + +void Quad::set_offset(const Vector2& p_offset){ + + offset=p_offset; + _update(); +} +Vector2 Quad::get_offset() const{ + + return offset; +} + +void Quad::set_centered(bool p_enabled){ + + centered=p_enabled; + _update(); +} +bool Quad::is_centered() const{ + + return centered; +} + +void Quad::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + if (pending_update) + _update(); + + + } break; + case NOTIFICATION_EXIT_SCENE: { + + pending_update=true; + + + } break; + } +} + +DVector<Face3> Quad::get_faces(uint32_t p_usage_flags) const { + + return DVector<Face3>(); +} + +AABB Quad::get_aabb() const { + + return aabb; +} + +void Quad::_bind_methods(){ + + ObjectTypeDB::bind_method(_MD("set_axis","axis"),&Quad::set_axis); + ObjectTypeDB::bind_method(_MD("get_axis"),&Quad::get_axis); + + ObjectTypeDB::bind_method(_MD("set_size","size"),&Quad::set_size); + ObjectTypeDB::bind_method(_MD("get_size"),&Quad::get_size); + + ObjectTypeDB::bind_method(_MD("set_centered","centered"),&Quad::set_centered); + ObjectTypeDB::bind_method(_MD("is_centered"),&Quad::is_centered); + + ObjectTypeDB::bind_method(_MD("set_offset","offset"),&Quad::set_offset); + ObjectTypeDB::bind_method(_MD("get_offset"),&Quad::get_offset); + + ADD_PROPERTY( PropertyInfo( Variant::INT, "quad/axis", PROPERTY_HINT_ENUM,"X,Y,Z" ), _SCS("set_axis"), _SCS("get_axis")); + ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "quad/size" ), _SCS("set_size"), _SCS("get_size")); + ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "quad/offset" ), _SCS("set_offset"), _SCS("get_offset")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "quad/centered" ), _SCS("set_centered"), _SCS("is_centered")); + +} + +Quad::Quad() { + + pending_update=true; + centered=true; + //offset=0; + size=Vector2(1,1); + axis=Vector3::AXIS_Z; + mesh=VisualServer::get_singleton()->mesh_create(); + set_base(mesh); + configured=false; + +} diff --git a/scene/3d/quad.h b/scene/3d/quad.h new file mode 100644 index 0000000000..7d1b4f5dc4 --- /dev/null +++ b/scene/3d/quad.h @@ -0,0 +1,76 @@ +/*************************************************************************/ +/* quad.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef QUAD_H +#define QUAD_H + + +#include "scene/3d/visual_instance.h" +#include "rid.h" + +class Quad : public GeometryInstance { + + OBJ_TYPE(Quad,GeometryInstance); + + Vector3::Axis axis; + bool centered; + Vector2 offset; + Vector2 size; + + AABB aabb; + bool configured; + bool pending_update; + RID mesh; + + void _update(); + +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_axis(Vector3::Axis p_axis); + Vector3::Axis get_axis() const; + + void set_size(const Vector2& p_sizze); + Vector2 get_size() const; + + void set_offset(const Vector2& p_offset); + Vector2 get_offset() const; + + void set_centered(bool p_enabled); + bool is_centered() const; + + virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; + virtual AABB get_aabb() const; + + Quad(); +}; + +#endif // QUAD_H diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp new file mode 100644 index 0000000000..e36e2da14f --- /dev/null +++ b/scene/3d/ray_cast.cpp @@ -0,0 +1,190 @@ +/*************************************************************************/ +/* ray_cast.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "ray_cast.h" + +#include "servers/physics_server.h" +#include "collision_object.h" +void RayCast::set_cast_to(const Vector3& p_point) { + + cast_to=p_point; + if (is_inside_scene() && get_scene()->is_editor_hint()) + update_gizmo(); + +} + +Vector3 RayCast::get_cast_to() const{ + + return cast_to; +} + +bool RayCast::is_colliding() const{ + + return collided; +} +Object *RayCast::get_collider() const{ + + if (against==0) + return NULL; + + return ObjectDB::get_instance(against); +} + +int RayCast::get_collider_shape() const { + + return against_shape; +} +Vector3 RayCast::get_collision_point() const{ + + return collision_point; +} +Vector3 RayCast::get_collision_normal() const{ + + return collision_normal; +} + + +void RayCast::set_enabled(bool p_enabled) { + + enabled=p_enabled; + if (is_inside_scene() && !get_scene()->is_editor_hint()) + set_fixed_process(p_enabled); + if (!p_enabled) + collided=false; + +} + + +bool RayCast::is_enabled() const { + + + return enabled; +} + + +void RayCast::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + if (enabled && !get_scene()->is_editor_hint()) { + set_fixed_process(true); + Node *p = get_parent(); + while( p && p->cast_to<Spatial>() ) { + + CollisionObject *co = p->cast_to<CollisionObject>(); + if (co) { + + exception=co->get_rid(); + exceptions.insert(exception); + } + + p=p->get_parent(); + } + } else + set_fixed_process(false); + + + + } break; + case NOTIFICATION_EXIT_SCENE: { + + if (enabled) { + set_fixed_process(false); + } + + exceptions.erase(exception); + + } break; + case NOTIFICATION_FIXED_PROCESS: { + + if (!enabled) + break; + + + + Ref<World> w3d = get_world(); + ERR_BREAK( w3d.is_null() ); + + PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(w3d->get_space()); + ERR_BREAK( !dss ); + + Transform gt = get_global_transform(); + + Vector3 to = cast_to; + if (to==Vector3()) + to=Vector3(0,0.01,0); + + PhysicsDirectSpaceState::RayResult rr; + + if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exceptions)) { + + collided=true; + against=rr.collider_id; + collision_point=rr.position; + collision_normal=rr.normal; + against_shape=rr.shape; + } else { + collided=false; + } + + + + } break; + } +} + +void RayCast::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&RayCast::set_enabled); + ObjectTypeDB::bind_method(_MD("is_enabled"),&RayCast::is_enabled); + + ObjectTypeDB::bind_method(_MD("set_cast_to","local_point"),&RayCast::set_cast_to); + ObjectTypeDB::bind_method(_MD("get_cast_to"),&RayCast::get_cast_to); + + ObjectTypeDB::bind_method(_MD("is_colliding"),&RayCast::is_colliding); + + ObjectTypeDB::bind_method(_MD("get_collider"),&RayCast::get_collider); + ObjectTypeDB::bind_method(_MD("get_collider_shape"),&RayCast::get_collider_shape); + ObjectTypeDB::bind_method(_MD("get_collision_point"),&RayCast::get_collision_point); + ObjectTypeDB::bind_method(_MD("get_collision_normal"),&RayCast::get_collision_normal); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to")); +} + +RayCast::RayCast() { + + enabled=false; + against=0; + collided=false; + against_shape=0; + cast_to=Vector3(0,-1,0); +} diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h new file mode 100644 index 0000000000..96606b1628 --- /dev/null +++ b/scene/3d/ray_cast.h @@ -0,0 +1,72 @@ +/*************************************************************************/ +/* ray_cast.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef RAY_CAST_H +#define RAY_CAST_H + +#include "scene/3d/spatial.h" + +class RayCast : public Spatial { + + OBJ_TYPE(RayCast,Spatial); + + + bool enabled; + bool collided; + ObjectID against; + int against_shape; + Vector3 collision_point; + Vector3 collision_normal; + + Vector3 cast_to; + + RID exception; + Set<RID> exceptions; + +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_enabled(bool p_enabled); + bool is_enabled() const; + + void set_cast_to(const Vector3& p_point); + Vector3 get_cast_to() const; + + bool is_colliding() const; + Object *get_collider() const; + int get_collider_shape() const; + Vector3 get_collision_point() const; + Vector3 get_collision_normal() const; + + RayCast(); +}; + +#endif // RAY_CAST_H diff --git a/scene/3d/room_instance.cpp b/scene/3d/room_instance.cpp new file mode 100644 index 0000000000..0f390c15af --- /dev/null +++ b/scene/3d/room_instance.cpp @@ -0,0 +1,299 @@ +/*************************************************************************/ +/* room_instance.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "room_instance.h" + +#include "servers/visual_server.h" + +#include "geometry.h" +#include "globals.h" +#include "scene/resources/surface_tool.h" + + +void Room::_notification(int p_what) { + + switch(p_what) { + case NOTIFICATION_ENTER_WORLD: { + // go find parent level + Node *parent_room=get_parent(); + level=0; + + while(parent_room) { + + Room *r = parent_room->cast_to<Room>(); + if (r) { + + level=r->level+1; + break; + } + + parent_room=parent_room->get_parent(); + } + + + if (sound_enabled) + SpatialSoundServer::get_singleton()->room_set_space(sound_room,get_world()->get_sound_space()); + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + SpatialSoundServer::get_singleton()->room_set_transform(sound_room,get_global_transform()); + } break; + case NOTIFICATION_EXIT_WORLD: { + + if (sound_enabled) + SpatialSoundServer::get_singleton()->room_set_space(sound_room,RID()); + + + } break; + } + +} + + +RES Room::_get_gizmo_geometry() const { + + DVector<Face3> faces; + if (!room.is_null()) + faces=room->get_geometry_hint(); + + int count=faces.size(); + if (count==0) + return RES(); + + DVector<Face3>::Read facesr=faces.read(); + + const Face3* facesptr=facesr.ptr(); + + DVector<Vector3> points; + + Ref<SurfaceTool> surface_tool( memnew( SurfaceTool )); + + Ref<FixedMaterial> mat( memnew( FixedMaterial )); + + mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.2,0.8,0.9,0.3) ); + mat->set_line_width(4); + mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); + mat->set_flag(Material::FLAG_UNSHADED,true); + mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true); + + surface_tool->begin(Mesh::PRIMITIVE_LINES); + surface_tool->set_material(mat); + + for (int i=0;i<count;i++) { + + surface_tool->add_vertex(facesptr[i].vertex[0]); + surface_tool->add_vertex(facesptr[i].vertex[1]); + + surface_tool->add_vertex(facesptr[i].vertex[1]); + surface_tool->add_vertex(facesptr[i].vertex[2]); + + surface_tool->add_vertex(facesptr[i].vertex[2]); + surface_tool->add_vertex(facesptr[i].vertex[0]); + + } + + return surface_tool->commit(); +} + + + +AABB Room::get_aabb() const { + + if (room.is_null()) + return AABB(); + + return room->get_bounds().get_aabb(); +} +DVector<Face3> Room::get_faces(uint32_t p_usage_flags) const { + + return DVector<Face3>(); + +} + +void Room::set_room( const Ref<RoomBounds>& p_room ) { + + room=p_room; + update_gizmo(); + + if (room.is_valid()) { + + set_base(room->get_rid()); + } else { + set_base(RID()); + } + + if (!is_inside_scene()) + return; + + + propagate_notification(NOTIFICATION_AREA_CHANGED); + update_gizmo(); + + if (room.is_valid()) + SpatialSoundServer::get_singleton()->room_set_bounds(sound_room,room->get_bounds()); + + +} + +Ref<RoomBounds> Room::get_room() const { + + return room; +} + +void Room::_parse_node_faces(DVector<Face3> &all_faces,const Node *p_node) const { + + const VisualInstance *vi=p_node->cast_to<VisualInstance>(); + + if (vi) { + DVector<Face3> faces=vi->get_faces(FACES_ENCLOSING); + + if (faces.size()) { + int old_len=all_faces.size(); + all_faces.resize( all_faces.size() + faces.size() ); + int new_len=all_faces.size(); + DVector<Face3>::Write all_facesw=all_faces.write(); + Face3 * all_facesptr=all_facesw.ptr(); + + DVector<Face3>::Read facesr=faces.read(); + const Face3 * facesptr=facesr.ptr(); + + Transform tr=vi->get_relative_transform(this); + + for(int i=old_len;i<new_len;i++) { + + Face3 f=facesptr[i-old_len]; + for (int j=0;j<3;j++) + f.vertex[j]=tr.xform(f.vertex[j]); + all_facesptr[i]=f; + } + } + } + + + for (int i=0;i<p_node->get_child_count();i++) { + + _parse_node_faces(all_faces,p_node->get_child(i)); + } + +} + +void Room::compute_room_from_subtree() { + + + DVector<Face3> all_faces; + _parse_node_faces(all_faces,this); + + + if (all_faces.size()==0) + return; + float error; + DVector<Face3> wrapped_faces = Geometry::wrap_geometry(all_faces,&error); + + + if (wrapped_faces.size()==0) + return; + + BSP_Tree tree(wrapped_faces,error); + + Ref<RoomBounds> room( memnew( RoomBounds ) ); + room->set_bounds(tree); + room->set_geometry_hint(wrapped_faces); + + set_room(room); + +} + + + +void Room::set_simulate_acoustics(bool p_enable) { + + if (sound_enabled==p_enable) + return; + + sound_enabled=p_enable; + if (!is_inside_world()) + return; //nothing to do + + if (sound_enabled) + SpatialSoundServer::get_singleton()->room_set_space(sound_room,get_world()->get_sound_space()); + else + SpatialSoundServer::get_singleton()->room_set_space(sound_room,RID()); + + +} + +void Room::_bounds_changed() { + + update_gizmo(); +} + +bool Room::is_simulating_acoustics() const { + + return sound_enabled; +} + + + +RID Room::get_sound_room() const { + + return RID(); +} + +void Room::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_room","room:Room"),&Room::set_room ); + ObjectTypeDB::bind_method(_MD("get_room:Room"),&Room::get_room ); + ObjectTypeDB::bind_method(_MD("compute_room_from_subtree"),&Room::compute_room_from_subtree); + + + + ObjectTypeDB::bind_method(_MD("set_simulate_acoustics","enable"),&Room::set_simulate_acoustics ); + ObjectTypeDB::bind_method(_MD("is_simulating_acoustics"),&Room::is_simulating_acoustics ); + + + + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "room/room", PROPERTY_HINT_RESOURCE_TYPE, "Area" ), _SCS("set_room"), _SCS("get_room") ); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "room/simulate_acoustics"), _SCS("set_simulate_acoustics"), _SCS("is_simulating_acoustics") ); +} + + +Room::Room() { + + sound_enabled=false; + sound_room=SpatialSoundServer::get_singleton()->room_create(); + + level=0; + +} + + +Room::~Room() { + + SpatialSoundServer::get_singleton()->free(sound_room); +} + diff --git a/scene/3d/room_instance.h b/scene/3d/room_instance.h new file mode 100644 index 0000000000..1d11630cef --- /dev/null +++ b/scene/3d/room_instance.h @@ -0,0 +1,102 @@ +/*************************************************************************/ +/* room_instance.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef ROOM_INSTANCE_H +#define ROOM_INSTANCE_H + +#include "scene/3d/visual_instance.h" +#include "scene/resources/room.h" +#include "servers/spatial_sound_server.h" +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + + +/* RoomInstance Logic: + a) Instances that belong to the room are drawn only if the room is visible (seen through portal, or player inside) + b) Instances that don't belong to any room are considered to belong to the root room (RID empty) + c) "dynamic" Instances are assigned to the rooms their AABB touch + +*/ + + +class Room : public VisualInstance { + + OBJ_TYPE( Room, VisualInstance ); +public: + + + + +private: + Ref<RoomBounds> room; + + RID sound_room; + + bool sound_enabled; + + int level; + void _parse_node_faces(DVector<Face3> &all_faces,const Node *p_node) const; + + + void _bounds_changed(); + virtual RES _get_gizmo_geometry() const; + +protected: + + void _notification(int p_what); + + static void _bind_methods(); + +public: + + enum { + // used to notify portals that the room in which they are has changed. + NOTIFICATION_AREA_CHANGED=60 + }; + + virtual AABB get_aabb() const; + virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; + + void set_room( const Ref<RoomBounds>& p_room ); + Ref<RoomBounds> get_room() const; + + void set_simulate_acoustics(bool p_enable); + bool is_simulating_acoustics() const; + + void compute_room_from_subtree(); + + RID get_sound_room() const; + + Room(); + ~Room(); + +}; + + +#endif // ROOM_INSTANCE_H diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp new file mode 100644 index 0000000000..05546ee4db --- /dev/null +++ b/scene/3d/scenario_fx.cpp @@ -0,0 +1,74 @@ +/*************************************************************************/ +/* scenario_fx.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "scenario_fx.h" + + + +void WorldEnvironment::_notification(int p_what) { + + + if (p_what==NOTIFICATION_ENTER_WORLD) { + + get_world()->set_environment(environment); + } else if (p_what==NOTIFICATION_EXIT_WORLD) { + + get_world()->set_environment(Ref<Environment>()); + } +} + +void WorldEnvironment::set_environment(const Ref<Environment>& p_environment) { + + environment=p_environment; + if (is_inside_world()) { + get_world()->set_environment(environment); + } + +} + +Ref<Environment> WorldEnvironment::get_environment() const { + + return environment; +} + + +void WorldEnvironment::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_environment","env:Environment"),&WorldEnvironment::set_environment); + ObjectTypeDB::bind_method(_MD("get_environment:Environment"),&WorldEnvironment::get_environment); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"environment",PROPERTY_HINT_RESOURCE_TYPE,"Environment"),_SCS("set_environment"),_SCS("get_environment")); + +} + + +WorldEnvironment::WorldEnvironment() { + + +} + + diff --git a/scene/3d/scenario_fx.h b/scene/3d/scenario_fx.h new file mode 100644 index 0000000000..b8b06ea983 --- /dev/null +++ b/scene/3d/scenario_fx.h @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* scenario_fx.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SCENARIO_FX_H +#define SCENARIO_FX_H + +#include "scene/3d/spatial.h" + + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + + +class WorldEnvironment : public Spatial { + + OBJ_TYPE(WorldEnvironment,Spatial ); + + Ref<Environment> environment; + +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + void set_environment(const Ref<Environment>& p_environment); + Ref<Environment> get_environment() const; + + WorldEnvironment(); + +}; + +#endif diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp new file mode 100644 index 0000000000..6ec23f96fb --- /dev/null +++ b/scene/3d/skeleton.cpp @@ -0,0 +1,536 @@ +/*************************************************************************/ +/* skeleton.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "skeleton.h" + +#include "message_queue.h" + +#include "scene/resources/surface_tool.h" +#include "core/globals.h" + + +bool Skeleton::_set(const StringName& p_path, const Variant& p_value) { + + String path = p_path; + + if (!path.begins_with("bones/")) + return false; + + int which=path.get_slice("/",1).to_int(); + String what=path.get_slice("/",2); + + if (which==bones.size() && what=="name") { + + add_bone(p_value); + return true; + } + + ERR_FAIL_INDEX_V( which, bones.size(), false ); + + if (what=="parent") + set_bone_parent(which, p_value ); + else if (what=="rest") + set_bone_rest(which, p_value); + else if (what=="enabled") + set_bone_enabled(which, p_value); + else if (what=="pose") + set_bone_pose(which, p_value); + else if (what=="bound_childs") { + Array children=p_value; + + bones[which].nodes_bound.clear(); + + for (int i=0;i<children.size();i++) { + + NodePath path=children[i]; + ERR_CONTINUE( path.operator String()=="" ); + Node *node = get_node(path); + ERR_CONTINUE(!node); + bind_child_node_to_bone(which,node); + } + } else { + return false; + } + + return true; +} + +bool Skeleton::_get(const StringName& p_name,Variant &r_ret) const { + + String path=p_name; + + if (!path.begins_with("bones/")) + return false; + + int which=path.get_slice("/",1).to_int(); + String what=path.get_slice("/",2); + + ERR_FAIL_INDEX_V( which, bones.size(), false ); + + if (what=="name") + r_ret=get_bone_name(which); + if (what=="parent") + r_ret=get_bone_parent(which); + else if (what=="rest") + r_ret=get_bone_rest(which); + else if (what=="enabled") + r_ret=is_bone_enabled(which); + else if (what=="pose") + r_ret=get_bone_pose(which); + else if (what=="bound_childs") { + Array children; + + for (const List<uint32_t>::Element *E=bones[which].nodes_bound.front();E;E=E->next()) { + + Object *obj=ObjectDB::get_instance(E->get()); + ERR_CONTINUE(!obj); + Node *node=obj->cast_to<Node>(); + ERR_CONTINUE(!node); + NodePath path=get_path_to(node); + children.push_back(path); + + } + + r_ret=children; + } else + return false; + + return true; + +} +void Skeleton::_get_property_list( List<PropertyInfo>* p_list ) const { + + for (int i=0;i<bones.size();i++) { + + String prep="bones/"+itos(i)+"/"; + p_list->push_back( PropertyInfo( Variant::STRING, prep+"name" ) ); + p_list->push_back( PropertyInfo( Variant::INT, prep+"parent" , PROPERTY_HINT_RANGE,"-1,"+itos(i-1)+",1") ); + p_list->push_back( PropertyInfo( Variant::TRANSFORM, prep+"rest" ) ); + p_list->push_back( PropertyInfo( Variant::BOOL, prep+"enabled" ) ); + p_list->push_back( PropertyInfo( Variant::TRANSFORM, prep+"pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ) ); + p_list->push_back( PropertyInfo( Variant::ARRAY, prep+"bound_childs" ) ); + } +} + +void Skeleton::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_WORLD: { + + if (dirty) { + + dirty=false; + _make_dirty(); // property make it dirty + } + + } break; + case NOTIFICATION_EXIT_WORLD: { + + } break; + case NOTIFICATION_UPDATE_SKELETON: { + + + VisualServer *vs=VisualServer::get_singleton(); + Bone *bonesptr=&bones[0]; + int len=bones.size(); + + vs->skeleton_resize( skeleton, len ); // if same size, nothin really happens + + // pose changed, rebuild cache of inverses + if (rest_global_inverse_dirty) { + + // calculate global rests and invert them + for (int i=0;i<len;i++) { + Bone &b=bonesptr[i]; + if (b.parent>=0) + b.rest_global_inverse=bonesptr[b.parent].rest_global_inverse * b.rest; + else + b.rest_global_inverse=b.rest; + } + for (int i=0;i<len;i++) { + Bone &b=bonesptr[i]; + b.rest_global_inverse.affine_invert(); + } + + rest_global_inverse_dirty=false; + + } + + for (int i=0;i<len;i++) { + + Bone &b=bonesptr[i]; + + if (b.enabled) { + + Transform pose=b.pose; + if (b.custom_pose_enable) { + + pose = b.custom_pose * pose; + } + + if (b.parent>=0) { + + b.pose_global=bonesptr[b.parent].pose_global * (b.rest * pose); + } else { + + b.pose_global=b.rest * pose; + } + } else { + + if (b.parent>=0) { + + b.pose_global=bonesptr[b.parent].pose_global * b.rest; + } else { + + b.pose_global=b.rest; + } + } + + vs->skeleton_bone_set_transform( skeleton, i, b.pose_global * b.rest_global_inverse ); + + for(List<uint32_t>::Element *E=b.nodes_bound.front();E;E=E->next()) { + + Object *obj=ObjectDB::get_instance(E->get()); + ERR_CONTINUE(!obj); + Spatial *sp = obj->cast_to<Spatial>(); + ERR_CONTINUE(!sp); + sp->set_transform(b.pose_global * b.rest_global_inverse); + } + } + + dirty=false; + } break; + } +} + +Transform Skeleton::get_bone_transform(int p_bone) const { + ERR_FAIL_INDEX_V(p_bone,bones.size(),Transform()); + if (dirty) + const_cast<Skeleton*>(this)->notification(NOTIFICATION_UPDATE_SKELETON); + return bones[p_bone].pose_global * bones[p_bone].rest_global_inverse; +} + +RID Skeleton::get_skeleton() const { + + return skeleton; +} + +// skeleton creation api +void Skeleton::add_bone(const String& p_name) { + + ERR_FAIL_COND( p_name=="" || p_name.find(":")!=-1 || p_name.find("/")!=-1 ); + + for (int i=0;i<bones.size();i++) { + + ERR_FAIL_COND( bones[i].name=="p_name"); + } + + Bone b; + b.name=p_name; + bones.push_back(b); + + rest_global_inverse_dirty=true; + _make_dirty(); + update_gizmo(); +} +int Skeleton::find_bone(String p_name) const { + + for (int i=0;i<bones.size();i++) { + + if (bones[i].name==p_name) + return i; + } + + return -1; +} +String Skeleton::get_bone_name(int p_bone) const { + + ERR_FAIL_INDEX_V( p_bone, bones.size(), "" ); + + return bones[p_bone].name; +} + +int Skeleton::get_bone_count() const { + + return bones.size(); +} + +void Skeleton::set_bone_parent(int p_bone, int p_parent) { + + ERR_FAIL_INDEX( p_bone, bones.size() ); + ERR_FAIL_COND( p_parent!=-1 && (p_parent<0 || p_parent>=p_bone)); + + bones[p_bone].parent=p_parent; + rest_global_inverse_dirty=true; + _make_dirty(); +} + +int Skeleton::get_bone_parent(int p_bone) const { + + ERR_FAIL_INDEX_V( p_bone, bones.size(), -1 ); + + return bones[p_bone].parent; +} + +void Skeleton::set_bone_rest(int p_bone, const Transform& p_rest) { + + ERR_FAIL_INDEX( p_bone, bones.size() ); + + bones[p_bone].rest=p_rest; + rest_global_inverse_dirty=true; + _make_dirty(); + +} +Transform Skeleton::get_bone_rest(int p_bone) const { + + ERR_FAIL_INDEX_V( p_bone, bones.size(), Transform() ); + + return bones[p_bone].rest; + +} + +void Skeleton::set_bone_enabled(int p_bone, bool p_enabled) { + + ERR_FAIL_INDEX( p_bone, bones.size() ); + + bones[p_bone].enabled=p_enabled; + rest_global_inverse_dirty=true; + _make_dirty(); +} +bool Skeleton::is_bone_enabled(int p_bone) const { + + ERR_FAIL_INDEX_V( p_bone, bones.size(), false ); + return bones[p_bone].enabled; + +} + +void Skeleton::bind_child_node_to_bone(int p_bone,Node *p_node) { + + ERR_FAIL_NULL(p_node); + ERR_FAIL_INDEX( p_bone, bones.size() ); + + uint32_t id=p_node->get_instance_ID(); + + for (List<uint32_t>::Element *E=bones[p_bone].nodes_bound.front();E;E=E->next()) { + + if (E->get()==id) + return; // already here + } + + bones[p_bone].nodes_bound.push_back(id); + +} +void Skeleton::unbind_child_node_from_bone(int p_bone,Node *p_node) { + + ERR_FAIL_NULL(p_node); + ERR_FAIL_INDEX( p_bone, bones.size() ); + + uint32_t id=p_node->get_instance_ID(); + bones[p_bone].nodes_bound.erase(id); + +} +void Skeleton::get_bound_child_nodes_to_bone(int p_bone,List<Node*> *p_bound) const { + + ERR_FAIL_INDEX( p_bone, bones.size() ); + + for (const List<uint32_t>::Element *E=bones[p_bone].nodes_bound.front();E;E=E->next()) { + + Object *obj=ObjectDB::get_instance(E->get()); + ERR_CONTINUE(!obj); + p_bound->push_back(obj->cast_to<Node>()); + } + +} + +void Skeleton::clear_bones() { + + bones.clear(); + rest_global_inverse_dirty=true; + _make_dirty(); +} + +// posing api + +void Skeleton::set_bone_pose(int p_bone, const Transform& p_pose) { + + ERR_FAIL_INDEX( p_bone, bones.size() ); + ERR_FAIL_COND( !is_inside_scene() ); + + + bones[p_bone].pose=p_pose; + _make_dirty(); +} +Transform Skeleton::get_bone_pose(int p_bone) const { + + ERR_FAIL_INDEX_V( p_bone, bones.size(), Transform() ); + return bones[p_bone].pose; + +} + +void Skeleton::set_bone_custom_pose(int p_bone, const Transform& p_custom_pose) { + + ERR_FAIL_INDEX( p_bone, bones.size() ); +// ERR_FAIL_COND( !is_inside_scene() ); + + + bones[p_bone].custom_pose_enable=(p_custom_pose!=Transform()); + bones[p_bone].custom_pose=p_custom_pose; + + _make_dirty(); +} + +Transform Skeleton::get_bone_custom_pose(int p_bone) const { + + ERR_FAIL_INDEX_V( p_bone, bones.size(), Transform() ); + return bones[p_bone].custom_pose; + +} + + +void Skeleton::_make_dirty() { + + if (dirty) + return; + + if (!is_inside_scene()) { + dirty=true; + return; + } + MessageQueue::get_singleton()->push_notification( this, NOTIFICATION_UPDATE_SKELETON ); + dirty=true; +} + + +RES Skeleton::_get_gizmo_geometry() const { + + if (!GLOBAL_DEF("debug/draw_skeleton", true)) + return RES(); + + if (bones.size()==0) + return RES(); + + Ref<SurfaceTool> surface_tool( memnew( SurfaceTool )); + + Ref<FixedMaterial> mat( memnew( FixedMaterial )); + + mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.6,1.0,0.3,0.1) ); + mat->set_line_width(4); + mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); + mat->set_flag(Material::FLAG_UNSHADED,true); + mat->set_flag(Material::FLAG_ONTOP,true); + mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true); + + surface_tool->begin(Mesh::PRIMITIVE_LINES); + surface_tool->set_material(mat); + + + const Bone *bonesptr=&bones[0]; + int len=bones.size(); + + for (int i=0;i<len;i++) { + + const Bone &b=bonesptr[i]; + + Transform t; + if (b.parent<0) + continue; + + Vector3 v1=(bonesptr[b.parent].pose_global * bonesptr[b.parent].rest_global_inverse).xform(bonesptr[b.parent].rest_global_inverse.affine_inverse().origin); + Vector3 v2=(b.pose_global * b.rest_global_inverse).xform(b.rest_global_inverse.affine_inverse().origin); + + surface_tool->add_vertex(v1); + surface_tool->add_vertex(v2); + + } + + return surface_tool->commit(); + +} + +void Skeleton::localize_rests() { + + for(int i=bones.size()-1;i>=0;i--) { + + if (bones[i].parent>=0) + set_bone_rest(i,bones[bones[i].parent].rest.affine_inverse() * bones[i].rest); + } +} + + + +void Skeleton::_bind_methods() { + + + + + ObjectTypeDB::bind_method(_MD("add_bone","name"),&Skeleton::add_bone); + ObjectTypeDB::bind_method(_MD("find_bone","name"),&Skeleton::find_bone); + ObjectTypeDB::bind_method(_MD("get_bone_name","bone_idx"),&Skeleton::get_bone_name); + + ObjectTypeDB::bind_method(_MD("get_bone_parent","bone_idx"),&Skeleton::get_bone_parent); + ObjectTypeDB::bind_method(_MD("set_bone_parent","bone_idx","parent_idx"),&Skeleton::set_bone_parent); + + ObjectTypeDB::bind_method(_MD("get_bone_count"),&Skeleton::get_bone_count); + + ObjectTypeDB::bind_method(_MD("get_bone_rest","bone_idx"),&Skeleton::get_bone_rest); + ObjectTypeDB::bind_method(_MD("set_bone_rest","bone_idx","rest"),&Skeleton::set_bone_rest); + + ObjectTypeDB::bind_method(_MD("bind_child_node_to_bone","bone_idx","node:Node"),&Skeleton::bind_child_node_to_bone); + ObjectTypeDB::bind_method(_MD("unbind_child_node_from_bone","bone_idx","node:Node"),&Skeleton::unbind_child_node_from_bone); + ObjectTypeDB::bind_method(_MD("get_bound_child_nodes_to_bone","bone_idx"),&Skeleton::_get_bound_child_nodes_to_bone); + + ObjectTypeDB::bind_method(_MD("clear_bones"),&Skeleton::clear_bones); + + ObjectTypeDB::bind_method(_MD("get_bone_pose","bone_idx"),&Skeleton::get_bone_pose); + ObjectTypeDB::bind_method(_MD("set_bone_pose","bone_idx","pose"),&Skeleton::set_bone_pose); + + ObjectTypeDB::bind_method(_MD("get_bone_custom_pose","bone_idx"),&Skeleton::get_bone_custom_pose); + ObjectTypeDB::bind_method(_MD("set_bone_custom_pose","bone_idx","custom_pose"),&Skeleton::set_bone_custom_pose); + + ObjectTypeDB::bind_method(_MD("get_bone_transform","bone_idx"),&Skeleton::get_bone_transform); + + BIND_CONSTANT( NOTIFICATION_UPDATE_SKELETON ); +} + + + +Skeleton::Skeleton() { + + rest_global_inverse_dirty=true; + dirty=false; + skeleton=VisualServer::get_singleton()->skeleton_create(); +} + + +Skeleton::~Skeleton() { + + VisualServer::get_singleton()->free( skeleton ); +} + + diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h new file mode 100644 index 0000000000..c95734fbf1 --- /dev/null +++ b/scene/3d/skeleton.h @@ -0,0 +1,144 @@ +/*************************************************************************/ +/* skeleton.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SKELETON_H +#define SKELETON_H + +#include "scene/3d/spatial.h" +#include "rid.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class Skeleton : public Spatial { + + OBJ_TYPE( Skeleton, Spatial ); + + struct Bone { + + String name; + + bool enabled; + int parent; + + Transform rest; + Transform rest_global_inverse; + + Transform pose; + Transform pose_global; + + bool custom_pose_enable; + Transform custom_pose; + + List<uint32_t> nodes_bound; + + Bone() { parent=-1; enabled=true; custom_pose_enable=false; } + }; + + bool rest_global_inverse_dirty; + + Vector<Bone> bones; + + RID skeleton; + + void _make_dirty(); + bool dirty; + +//bind helpers + Array _get_bound_child_nodes_to_bone(int p_bone) const { + + Array bound; + List<Node*> childs; + get_bound_child_nodes_to_bone(p_bone,&childs); + + for (int i=0;i<childs.size();i++) { + + bound.push_back( childs[i] ); + } + return bound; + } + + virtual RES _get_gizmo_geometry() const; + +protected: + + bool _get(const StringName& p_name,Variant &r_ret) const; + bool _set(const StringName& p_name, const Variant& p_value); + void _get_property_list( List<PropertyInfo>* p_list ) const; + void _notification(int p_what); + static void _bind_methods(); + +public: + + enum { + + NOTIFICATION_UPDATE_SKELETON=50 + }; + + + RID get_skeleton() const; + + // skeleton creation api + void add_bone(const String&p_name); + int find_bone(String p_name) const; + String get_bone_name(int p_bone) const; + + void set_bone_parent(int p_bone, int p_parent); + int get_bone_parent(int p_bone) const; + + int get_bone_count() const; + + void set_bone_rest(int p_bone, const Transform& p_rest); + Transform get_bone_rest(int p_bone) const; + Transform get_bone_transform(int p_bone) const; + + void set_bone_enabled(int p_bone, bool p_enabled); + bool is_bone_enabled(int p_bone) const; + + void bind_child_node_to_bone(int p_bone,Node *p_node); + void unbind_child_node_from_bone(int p_bone,Node *p_node); + void get_bound_child_nodes_to_bone(int p_bone,List<Node*> *p_bound) const; + + void clear_bones(); + + // posing api + + void set_bone_pose(int p_bone, const Transform& p_pose); + Transform get_bone_pose(int p_bone) const; + + void set_bone_custom_pose(int p_bone, const Transform& p_custom_pose); + Transform get_bone_custom_pose(int p_bone) const; + + void localize_rests(); // used for loaders and tools + + Skeleton(); + ~Skeleton(); + +}; + +#endif diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp new file mode 100644 index 0000000000..de1fd7e8c0 --- /dev/null +++ b/scene/3d/spatial.cpp @@ -0,0 +1,567 @@ +/*************************************************************************/ +/* spatial.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "spatial.h" + +#include "scene/main/viewport.h" +#include "message_queue.h" +#include "scene/scene_string_names.h" + +/* + + possible algorithms: + + Algorithm 1: (current) + + definition of invalidation: global is invalid + + 1) If a node sets a LOCAL, it produces an invalidation of everything above + a) If above is invalid, don't keep invalidating upwards + 2) If a node sets a GLOBAL, it is converted to LOCAL (and forces validation of everything pending below) + + drawback: setting/reading globals is useful and used very very often, and using affine inverses is slow + +--- + + Algorithm 2: (no longer current) + + definition of invalidation: NONE dirty, LOCAL dirty, GLOBAL dirty + + 1) If a node sets a LOCAL, it must climb the tree and set it as GLOBAL dirty + a) marking GLOBALs as dirty up all the tree must be done always + 2) If a node sets a GLOBAL, it marks local as dirty, and that's all? + + //is clearing the dirty state correct in this case? + + drawback: setting a local down the tree forces many tree walks often + +-- + +future: no idea + + */ + + + +SpatialGizmo::SpatialGizmo() { + +} + +void Spatial::_notify_dirty() { + + if (!data.ignore_notification && !xform_change.in_list()) { + + get_scene()->xform_change_list.add(&xform_change); + } +} + + + +void Spatial::_update_local_transform() const { + + data.local_transform.basis.set_euler(data.rotation); + data.local_transform.basis.scale(data.scale); + + data.dirty&=~DIRTY_LOCAL; +} +void Spatial::_propagate_transform_changed(Spatial *p_origin) { + + if (!is_inside_scene()) { + return; + } + +// if (data.dirty&DIRTY_GLOBAL) +// return; //already dirty + + data.children_lock++; + + for (List<Spatial*>::Element *E=data.children.front();E;E=E->next()) { + + if (E->get()->data.toplevel_active) + continue; //don't propagate to a toplevel + E->get()->_propagate_transform_changed(p_origin); + } + + + if (!data.ignore_notification && !xform_change.in_list()) { + + get_scene()->xform_change_list.add(&xform_change); + + } + data.dirty|=DIRTY_GLOBAL; + + data.children_lock--; +} + +void Spatial::_notification(int p_what) { + + switch(p_what) { + case NOTIFICATION_ENTER_SCENE: { + + Node *p = get_parent(); + if (p) + data.parent=p->cast_to<Spatial>(); + + if (data.parent) + data.C=data.parent->data.children.push_back(this); + else + data.C=NULL; + + if (data.toplevel && !get_scene()->is_editor_hint()) { + + if (data.parent) { + data.local_transform = data.parent->get_global_transform() * get_transform(); + data.dirty=DIRTY_VECTORS; //global is always dirty upon entering a scene + } + data.toplevel_active=true; + } + + data.dirty|=DIRTY_GLOBAL; //global is always dirty upon entering a scene + _notify_dirty(); + + notification(NOTIFICATION_ENTER_WORLD); + + } break; + case NOTIFICATION_EXIT_SCENE: { + + notification(NOTIFICATION_EXIT_WORLD,true); + if (xform_change.in_list()) + get_scene()->xform_change_list.remove(&xform_change); + if (data.C) + data.parent->data.children.erase(data.C); + data.parent=NULL; + data.C=NULL; + data.toplevel_active=false; + } break; + case NOTIFICATION_ENTER_WORLD: { + + data.inside_world=true; + data.viewport=NULL; + Node *parent = get_parent(); + while(parent && !data.viewport) { + data.viewport=parent->cast_to<Viewport>(); + parent=parent->get_parent(); + } + + ERR_FAIL_COND(!data.viewport); + + + if (get_script_instance()) { + + Variant::CallError err; + get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world,NULL,0); + } +#ifdef TOOLS_ENABLED + if (get_scene()->is_editor_hint()) { + +// get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this); + get_scene()->call_group(0,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this); + if (!data.gizmo_disabled) { + + if (data.gizmo.is_valid()) + data.gizmo->create(); + } + } +#endif + + } break; + case NOTIFICATION_EXIT_WORLD: { + +#ifdef TOOLS_ENABLED + if (data.gizmo.is_valid()) { + data.gizmo->free(); + } +#endif + + if (get_script_instance()) { + + Variant::CallError err; + get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_world,NULL,0); + } + + data.viewport=NULL; + data.inside_world=false; + + } break; + + + case NOTIFICATION_TRANSFORM_CHANGED: { + +#ifdef TOOLS_ENABLED + if (data.gizmo.is_valid()) { + data.gizmo->transform(); + } +#endif + } break; + + default: {} + } +} + +void Spatial::set_transform(const Transform& p_transform) { + + data.local_transform=p_transform; + data.dirty|=DIRTY_VECTORS; + _change_notify("transform/translation"); + _change_notify("transform/rotation"); + _change_notify("transform/scale"); + _propagate_transform_changed(this); + +} + +void Spatial::set_global_transform(const Transform& p_transform) { + + Transform xform = + (data.parent && !data.toplevel_active) ? + data.parent->get_global_transform().affine_inverse() * p_transform : + p_transform; + + set_transform(xform); + +} + + +Transform Spatial::get_transform() const { + + if (data.dirty & DIRTY_LOCAL) { + + _update_local_transform(); + } + + return data.local_transform; +} +Transform Spatial::get_global_transform() const { + + ERR_FAIL_COND_V(!is_inside_scene(), Transform()); + + if (data.dirty & DIRTY_GLOBAL) { + + if (data.dirty & DIRTY_LOCAL) { + + _update_local_transform(); + } + + if (data.parent && !data.toplevel_active) { + + data.global_transform=data.parent->get_global_transform() * data.local_transform; + } else { + + data.global_transform=data.local_transform; + } + + data.dirty&=~DIRTY_GLOBAL; + } + + return data.global_transform; +} +#if 0 +void Spatial::add_child_notify(Node *p_child) { +/* + Spatial *s=p_child->cast_to<Spatial>(); + if (!s) + return; + + ERR_FAIL_COND(data.children_lock>0); + + s->data.dirty=DIRTY_GLOBAL; // don't allow global transform to be valid + s->data.parent=this; + data.children.push_back(s); + s->data.C=data.children.back(); +*/ +} + +void Spatial::remove_child_notify(Node *p_child) { +/* + Spatial *s=p_child->cast_to<Spatial>(); + if (!s) + return; + + ERR_FAIL_COND(data.children_lock>0); + + if (s->data.C) + data.children.erase(s->data.C); + s->data.parent=NULL; + s->data.C=NULL; +*/ +} +#endif + +Spatial *Spatial::get_parent_spatial() const { + + return data.parent; + +} + +Transform Spatial::get_relative_transform(const Node *p_parent) const { + + if (p_parent==this) + return Transform(); + + ERR_FAIL_COND_V(!data.parent,Transform()); + + if (p_parent==data.parent) + return get_transform(); + else + return data.parent->get_relative_transform(p_parent) * get_transform(); + +} + +void Spatial::set_translation(const Vector3& p_translation) { + + data.local_transform.origin=p_translation; + _propagate_transform_changed(this); + +} + +void Spatial::set_rotation(const Vector3& p_euler){ + + if (data.dirty&DIRTY_VECTORS) { + data.scale=data.local_transform.basis.get_scale(); + data.dirty&=~DIRTY_VECTORS; + } + + data.rotation=p_euler; + data.dirty|=DIRTY_LOCAL; + _propagate_transform_changed(this); + +} +void Spatial::set_scale(const Vector3& p_scale){ + + if (data.dirty&DIRTY_VECTORS) { + data.rotation=data.local_transform.basis.get_euler(); + data.dirty&=~DIRTY_VECTORS; + } + + data.scale=p_scale; + data.dirty|=DIRTY_LOCAL; + _propagate_transform_changed(this); + +} + +Vector3 Spatial::get_translation() const{ + + return data.local_transform.origin; +} +Vector3 Spatial::get_rotation() const{ + + if (data.dirty&DIRTY_VECTORS) { + data.scale=data.local_transform.basis.get_scale(); + data.rotation=data.local_transform.basis.get_euler(); + data.dirty&=~DIRTY_VECTORS; + } + + return data.rotation; +} +Vector3 Spatial::get_scale() const{ + + if (data.dirty&DIRTY_VECTORS) { + data.scale=data.local_transform.basis.get_scale(); + data.rotation=data.local_transform.basis.get_euler(); + data.dirty&=~DIRTY_VECTORS; + } + + return data.scale; +} + + +void Spatial::update_gizmo() { + +#ifdef TOOLS_ENABLED + if (!is_inside_world()) + return; + if (!data.gizmo.is_valid()) + return; + if (data.gizmo_dirty) + return; + data.gizmo_dirty=true; + MessageQueue::get_singleton()->push_call(this,"_update_gizmo"); +#endif +} + +void Spatial::set_gizmo(const Ref<SpatialGizmo>& p_gizmo) { + +#ifdef TOOLS_ENABLED + + if (data.gizmo_disabled) + return; + if (data.gizmo.is_valid() && is_inside_world()) + data.gizmo->free(); + data.gizmo=p_gizmo; + if (data.gizmo.is_valid() && is_inside_world()) { + + data.gizmo->create(); + data.gizmo->redraw(); + data.gizmo->transform(); + } + +#endif +} + +Ref<SpatialGizmo> Spatial::get_gizmo() const { + +#ifdef TOOLS_ENABLED + + return data.gizmo; +#else + + return Ref<SpatialGizmo>(); +#endif +} + +#ifdef TOOLS_ENABLED + +void Spatial::_update_gizmo() { + + data.gizmo_dirty=false; + if (data.gizmo.is_valid()) + data.gizmo->redraw(); +} + + +void Spatial::set_disable_gizmo(bool p_enabled) { + + data.gizmo_disabled=p_enabled; + if (!p_enabled && data.gizmo.is_valid()) + data.gizmo=Ref<SpatialGizmo>(); +} + +#endif + +void Spatial::set_as_toplevel(bool p_enabled) { + + if (data.toplevel==p_enabled) + return; + if (is_inside_scene() && !get_scene()->is_editor_hint()) { + + if (p_enabled) + set_transform(get_global_transform()); + else if (data.parent) + set_transform(data.parent->get_global_transform().affine_inverse() * get_global_transform()); + + data.toplevel=p_enabled; + data.toplevel_active=p_enabled; + + } else { + data.toplevel=p_enabled; + } + +} + +bool Spatial::is_set_as_toplevel() const{ + + return data.toplevel; +} + +void Spatial::_set_rotation_deg(const Vector3& p_deg) { + + set_rotation(p_deg * Math_PI / 180.0); +} + +Vector3 Spatial::_get_rotation_deg() const { + + return get_rotation() * 180.0 / Math_PI; +} + +Ref<World> Spatial::get_world() const { + + ERR_FAIL_COND_V(!is_inside_world(),Ref<World>()); + return data.viewport->find_world(); + +} + + +void Spatial::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_transform","local"), &Spatial::set_transform); + ObjectTypeDB::bind_method(_MD("get_transform"), &Spatial::get_transform); + ObjectTypeDB::bind_method(_MD("set_translation","translation"), &Spatial::set_translation); + ObjectTypeDB::bind_method(_MD("get_translation"), &Spatial::get_translation); + ObjectTypeDB::bind_method(_MD("set_rotation","rotation"), &Spatial::set_rotation); + ObjectTypeDB::bind_method(_MD("get_rotation"), &Spatial::get_rotation); + ObjectTypeDB::bind_method(_MD("set_scale","scale"), &Spatial::set_scale); + ObjectTypeDB::bind_method(_MD("get_scale"), &Spatial::get_scale); + ObjectTypeDB::bind_method(_MD("set_global_transform","global"), &Spatial::set_global_transform); + ObjectTypeDB::bind_method(_MD("get_global_transform"), &Spatial::get_global_transform); + ObjectTypeDB::bind_method(_MD("get_parent_spatial"), &Spatial::get_parent_spatial); + ObjectTypeDB::bind_method(_MD("set_ignore_transform_notification","enabled"), &Spatial::set_ignore_transform_notification); + ObjectTypeDB::bind_method(_MD("set_as_toplevel","enable"), &Spatial::set_as_toplevel); + ObjectTypeDB::bind_method(_MD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel); + ObjectTypeDB::bind_method(_MD("_set_rotation_deg","rotation_deg"), &Spatial::_set_rotation_deg); + ObjectTypeDB::bind_method(_MD("_get_rotation_deg"), &Spatial::_get_rotation_deg); + ObjectTypeDB::bind_method(_MD("get_world:World"), &Spatial::get_world); + +#ifdef TOOLS_ENABLED + ObjectTypeDB::bind_method(_MD("_update_gizmo"), &Spatial::_update_gizmo); +#endif + + ObjectTypeDB::bind_method(_MD("update_gizmo"), &Spatial::update_gizmo); + ObjectTypeDB::bind_method(_MD("set_gizmo","gizmo:SpatialGizmo"), &Spatial::set_gizmo); + ObjectTypeDB::bind_method(_MD("get_gizmo:SpatialGizmo"), &Spatial::get_gizmo); + + BIND_CONSTANT( NOTIFICATION_TRANSFORM_CHANGED ); + BIND_CONSTANT( NOTIFICATION_ENTER_WORLD ); + BIND_CONSTANT( NOTIFICATION_EXIT_WORLD ); + + //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), _SCS("set_global_transform"), _SCS("get_global_transform") ); + ADD_PROPERTYNZ( PropertyInfo(Variant::TRANSFORM,"transform/local",PROPERTY_HINT_NONE,""), _SCS("set_transform"), _SCS("get_transform") ); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/translation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_translation"), _SCS("get_translation") ); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("_set_rotation_deg"), _SCS("_get_rotation_deg") ); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation_rad",PROPERTY_HINT_NONE,"",0), _SCS("set_rotation"), _SCS("get_rotation") ); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/scale",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_scale"), _SCS("get_scale") ); + //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), _SCS("set_transform"), _SCS("get_transform") ); + +} + + +Spatial::Spatial() : xform_change(this) +{ + + data.dirty=DIRTY_NONE; + data.children_lock=0; + + data.ignore_notification=false; + data.toplevel=false; + data.toplevel_active=false; + data.scale=Vector3(1,1,1); + data.viewport=NULL; + data.inside_world=false; +#ifdef TOOLS_ENABLED + data.gizmo_disabled=false; + data.gizmo_dirty=false; +#endif + data.parent=NULL; + data.C=NULL; + +} + + +Spatial::~Spatial() { + +} + + diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h new file mode 100644 index 0000000000..e10629f7de --- /dev/null +++ b/scene/3d/spatial.h @@ -0,0 +1,166 @@ +/*************************************************************************/ +/* spatial.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SPATIAL_H +#define SPATIAL_H + +#include "scene/main/node.h" +#include "scene/main/scene_main_loop.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + +class SpatialGizmo : public Reference { + + OBJ_TYPE(SpatialGizmo,Reference); + + +public: + + virtual void create()=0; + virtual void transform()=0; + virtual void redraw()=0; + virtual void free()=0; + + SpatialGizmo(); +}; + + +class Spatial : public Node { + + OBJ_TYPE( Spatial, Node ); + OBJ_CATEGORY("3D"); + + enum TransformDirty { + DIRTY_NONE=0, + DIRTY_VECTORS=1, + DIRTY_LOCAL=2, + DIRTY_GLOBAL=4 + }; + + mutable SelfList<Node> xform_change; + + struct Data { + + + + mutable Transform global_transform; + mutable Transform local_transform; + mutable Vector3 rotation; + mutable Vector3 scale; + + mutable int dirty; + + Viewport *viewport; + + + bool toplevel_active; + bool toplevel; + bool inside_world; + + int children_lock; + Spatial *parent; + List<Spatial*> children; + List<Spatial*>::Element *C; + + bool ignore_notification; + +#ifdef TOOLS_ENABLED + Ref<SpatialGizmo> gizmo; + bool gizmo_disabled; + bool gizmo_dirty; +#endif + + } data; +#ifdef TOOLS_ENABLED + + void _update_gizmo(); +#endif + void _notify_dirty(); + void _propagate_transform_changed(Spatial *p_origin); + + void _set_rotation_deg(const Vector3& p_deg); + Vector3 _get_rotation_deg() const; + + +protected: + + _FORCE_INLINE_ void set_ignore_transform_notification(bool p_ignore) { data.ignore_notification=p_ignore; } + + _FORCE_INLINE_ void _update_local_transform() const; + + void _notification(int p_what); + static void _bind_methods(); + +public: + + enum { + + NOTIFICATION_TRANSFORM_CHANGED=SceneMainLoop::NOTIFICATION_TRANSFORM_CHANGED, + NOTIFICATION_ENTER_WORLD=41, + NOTIFICATION_EXIT_WORLD=42, + }; + + Spatial *get_parent_spatial() const; + + + Ref<World> get_world() const; + + void set_translation(const Vector3& p_translation); + void set_rotation(const Vector3& p_euler); + void set_scale(const Vector3& p_scale); + + Vector3 get_translation() const; + Vector3 get_rotation() const; + Vector3 get_scale() const; + + void set_transform(const Transform& p_transform); + void set_global_transform(const Transform& p_transform); + + Transform get_transform() const; + Transform get_global_transform() const; + + void set_as_toplevel(bool p_enabled); + bool is_set_as_toplevel() const; + + void set_disable_gizmo(bool p_enabled); + void update_gizmo(); + void set_gizmo(const Ref<SpatialGizmo>& p_gizmo); + Ref<SpatialGizmo> get_gizmo() const; + + _FORCE_INLINE_ bool is_inside_world() const { return data.inside_world; } + + Transform get_relative_transform(const Node *p_parent) const; + + Spatial(); + ~Spatial(); + +}; + +#endif diff --git a/scene/3d/spatial_indexer.cpp b/scene/3d/spatial_indexer.cpp new file mode 100644 index 0000000000..261c62f51c --- /dev/null +++ b/scene/3d/spatial_indexer.cpp @@ -0,0 +1,165 @@ +/*************************************************************************/ +/* spatial_indexer.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "spatial_indexer.h" + +#if 0 + +#include "proximity_area.h" +#include "camera.h" +#include "scene/scene_string_names.h" + +void SpatialIndexer::add_camera(Camera* p_camera) { + + cameras.insert(p_camera); +} + +void SpatialIndexer::remove_camera(Camera* p_camera){ + + for (Set<ProximityArea*>::Element *F=proximity_areas.front();F;F=F->next()) { + + ProximityArea *prox = F->get(); + TK<Camera> k; + k.against=p_camera; + k.area=prox; + if (camera_pairs.has(k)) { + camera_pairs.erase(k); + prox->area_exit(ProximityArea::TRACK_CAMERAS,p_camera); + } + } + cameras.erase(p_camera); + +} + +void SpatialIndexer::update_camera(Camera* p_camera) { + + + _request_update(); +} + +void SpatialIndexer::_update_pairs() { + + // brute force interseciton code, no broadphase + // will implement broadphase in the future + + for (Set<Camera*>::Element *E=cameras.front();E;E=E->next()) { + + Camera *cam = E->get(); + Vector<Plane> cplanes = cam->get_frustum(); + + for (Set<ProximityArea*>::Element *F=proximity_areas.front();F;F=F->next()) { + + ProximityArea *prox = F->get(); + + bool inters=false; + + if (prox->get_track_flag(ProximityArea::TRACK_CAMERAS)) { + + AABB aabb = prox->get_global_transform().xform(prox->get_aabb()); + if (aabb.intersects_convex_shape(cplanes.ptr(),cplanes.size())) + inters=true; + } + + TK<Camera> k; + k.against=cam; + k.area=prox; + + bool has = camera_pairs.has(k); + + if (inters==has) + continue; + + if (inters) { + camera_pairs.insert(k); + prox->area_enter(ProximityArea::TRACK_CAMERAS,cam); + } else { + + camera_pairs.erase(k); + prox->area_exit(ProximityArea::TRACK_CAMERAS,cam); + } + } + + } + + pending_update=false; +} + +void SpatialIndexer::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("_update_pairs"),&SpatialIndexer::_update_pairs); +} + + +void SpatialIndexer::add_proximity_area(ProximityArea* p_area) { + + proximity_areas.insert(p_area); + +} + +void SpatialIndexer::remove_proximity_area(ProximityArea* p_area) { + + for (Set<Camera*>::Element *E=cameras.front();E;E=E->next()) { + + Camera *cam = E->get(); + TK<Camera> k; + k.against=cam; + k.area=p_area; + if (camera_pairs.has(k)) { + camera_pairs.erase(k); + p_area->area_exit(ProximityArea::TRACK_CAMERAS,cam); + } + } + proximity_areas.erase(p_area); + +} + +void SpatialIndexer::_request_update() { + + if (pending_update) + return; + pending_update=true; + call_deferred(SceneStringNames::get_singleton()->_update_pairs); + +} + +void SpatialIndexer::update_proximity_area_transform(ProximityArea* p_area) { + + _request_update(); +} + +void SpatialIndexer::update_proximity_area_flags(ProximityArea* p_area) { + + _request_update(); +} + +SpatialIndexer::SpatialIndexer() { + + pending_update=false; +} +#endif diff --git a/scene/3d/spatial_indexer.h b/scene/3d/spatial_indexer.h new file mode 100644 index 0000000000..d3038a1293 --- /dev/null +++ b/scene/3d/spatial_indexer.h @@ -0,0 +1,83 @@ +/*************************************************************************/ +/* spatial_indexer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SPATIAL_INDEXER_H +#define SPATIAL_INDEXER_H + +#include "scene/3d/spatial.h" +#if 0 + +class Camera; +class ProximityArea; + +class SpatialIndexer : public Object { + + OBJ_TYPE( SpatialIndexer, Object ); + + template<class T> + struct TK { + + T *against; + ProximityArea *area; + bool operator<(const TK<T>& p_k) const { return against==p_k.against ? area < p_k.area : against < p_k.against; } + }; + + + Set<Camera*> cameras; //cameras + Set<ProximityArea*> proximity_areas; + + Set<TK<Camera> > camera_pairs; + + bool pending_update; + void _update_pairs(); + void _request_update(); + +protected: + + static void _bind_methods(); + +friend class ProximityArea; +friend class Camera; + + void add_proximity_area(ProximityArea* p_area); + void remove_proximity_area(ProximityArea* p_area); + void update_proximity_area_transform(ProximityArea* p_area); + void update_proximity_area_flags(ProximityArea* p_area); + + void add_camera(Camera* p_camera); + void remove_camera(Camera* p_camera); + void update_camera(Camera* p_camera); + +public: + + + SpatialIndexer(); + +}; +#endif +#endif // SPATIAL_INDEXER_H diff --git a/scene/3d/spatial_player.cpp b/scene/3d/spatial_player.cpp new file mode 100644 index 0000000000..0847598356 --- /dev/null +++ b/scene/3d/spatial_player.cpp @@ -0,0 +1,272 @@ +/*************************************************************************/ +/* spatial_player.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "spatial_player.h" + +#include "servers/audio_server.h" +#include "camera.h" +#include "servers/spatial_sound_server.h" +#include "scene/resources/surface_tool.h" + + +void SpatialPlayer::_notification(int p_what) { + + + switch(p_what) { + + case NOTIFICATION_ENTER_WORLD: { + //find the sound space + + source_rid = SpatialSoundServer::get_singleton()->source_create(get_world()->get_sound_space()); + for(int i=0;i<PARAM_MAX;i++) + set_param(Param(i),params[i]); + + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + SpatialSoundServer::get_singleton()->source_set_transform(source_rid,get_global_transform()); + + } break; + case NOTIFICATION_EXIT_WORLD: { + + if (source_rid.is_valid()) + SpatialSoundServer::get_singleton()->free(source_rid); + + } break; + } + +} + + +void SpatialPlayer::set_param( Param p_param, float p_value) { + + ERR_FAIL_INDEX(p_param,PARAM_MAX); + params[p_param]=p_value; + if (p_param==PARAM_EMISSION_CONE_DEGREES) { + update_gizmo(); + } + if (source_rid.is_valid()) + SpatialSoundServer::get_singleton()->source_set_param(source_rid,(SpatialSoundServer::SourceParam)p_param,p_value); + +} + +float SpatialPlayer::get_param( Param p_param) const { + + ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0); + return params[p_param]; + +} + +bool SpatialPlayer::_can_gizmo_scale() const { + + return false; +} + +RES SpatialPlayer::_get_gizmo_geometry() const { + + Ref<SurfaceTool> surface_tool( memnew( SurfaceTool )); + + Ref<FixedMaterial> mat( memnew( FixedMaterial )); + + mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.0,0.6,0.7,0.05) ); + mat->set_parameter( FixedMaterial::PARAM_EMISSION,Color(0.5,0.7,0.8) ); + mat->set_blend_mode( Material::BLEND_MODE_ADD ); + mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); + mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true); + + + surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES); + surface_tool->set_material(mat); + + int sides=16; + int sections=24; + +// float len=1; + float deg=Math::deg2rad(params[PARAM_EMISSION_CONE_DEGREES]); + if (deg==180) + deg=179.5; + + Vector3 to=Vector3(0,0,-1); + + for(int j=0;j<sections;j++) { + + Vector3 p1=Matrix3(Vector3(1,0,0),deg*j/sections).xform(to); + Vector3 p2=Matrix3(Vector3(1,0,0),deg*(j+1)/sections).xform(to); + + for(int i=0;i<sides;i++) { + + Vector3 p1r = Matrix3(Vector3(0,0,1),Math_PI*2*float(i)/sides).xform(p1); + Vector3 p1s = Matrix3(Vector3(0,0,1),Math_PI*2*float(i+1)/sides).xform(p1); + Vector3 p2s = Matrix3(Vector3(0,0,1),Math_PI*2*float(i+1)/sides).xform(p2); + Vector3 p2r = Matrix3(Vector3(0,0,1),Math_PI*2*float(i)/sides).xform(p2); + + surface_tool->add_normal(p1r.normalized()); + surface_tool->add_vertex(p1r); + surface_tool->add_normal(p1s.normalized()); + surface_tool->add_vertex(p1s); + surface_tool->add_normal(p2s.normalized()); + surface_tool->add_vertex(p2s); + + surface_tool->add_normal(p1r.normalized()); + surface_tool->add_vertex(p1r); + surface_tool->add_normal(p2s.normalized()); + surface_tool->add_vertex(p2s); + surface_tool->add_normal(p2r.normalized()); + surface_tool->add_vertex(p2r); + + if (j==sections-1) { + + surface_tool->add_normal(p2r.normalized()); + surface_tool->add_vertex(p2r); + surface_tool->add_normal(p2s.normalized()); + surface_tool->add_vertex(p2s); + surface_tool->add_normal(Vector3(0,0,1)); + surface_tool->add_vertex(Vector3()); + } + } + } + + + Ref<Mesh> mesh = surface_tool->commit(); + + Ref<FixedMaterial> mat_speaker( memnew( FixedMaterial )); + + mat_speaker->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.3,0.3,0.6) ); + mat_speaker->set_parameter( FixedMaterial::PARAM_SPECULAR,Color(0.5,0.5,0.6) ); + //mat_speaker->set_blend_mode( Material::BLEND_MODE_MIX); + //mat_speaker->set_flag(Material::FLAG_DOUBLE_SIDED,false); + //mat_speaker->set_flag(Material::FLAG_UNSHADED,true); + + surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES); + surface_tool->set_material(mat_speaker); + +// float radius=1; + + + const int speaker_points=8; + Vector3 speaker[speaker_points]={ + Vector3(0,0,1)*0.15, + Vector3(1,1,1)*0.15, + Vector3(1,1,0)*0.15, + Vector3(2,2,-1)*0.15, + Vector3(1,1,-1)*0.15, + Vector3(0.8,0.8,-1.2)*0.15, + Vector3(0.5,0.5,-1.4)*0.15, + Vector3(0.0,0.0,-1.6)*0.15 + }; + + int speaker_sides=10; + + + for(int i = 0; i < speaker_sides ; i++) { + + + Matrix3 ma(Vector3(0,0,1),Math_PI*2*float(i)/speaker_sides); + Matrix3 mb(Vector3(0,0,1),Math_PI*2*float(i+1)/speaker_sides); + + + for(int j=0;j<speaker_points-1;j++) { + + Vector3 points[4]={ + ma.xform(speaker[j]), + mb.xform(speaker[j]), + mb.xform(speaker[j+1]), + ma.xform(speaker[j+1]), + }; + + Vector3 n = -Plane(points[0],points[1],points[2]).normal; + + surface_tool->add_normal(n); + surface_tool->add_vertex(points[0]); + surface_tool->add_normal(n); + surface_tool->add_vertex(points[2]); + surface_tool->add_normal(n); + surface_tool->add_vertex(points[1]); + + surface_tool->add_normal(n); + surface_tool->add_vertex(points[0]); + surface_tool->add_normal(n); + surface_tool->add_vertex(points[3]); + surface_tool->add_normal(n); + surface_tool->add_vertex(points[2]); + + + } + + + } + + + return surface_tool->commit(mesh); + +} + + +void SpatialPlayer::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_param","param","value"),&SpatialPlayer::set_param); + ObjectTypeDB::bind_method(_MD("get_param","param"),&SpatialPlayer::get_param); + + BIND_CONSTANT( PARAM_VOLUME_DB ); + BIND_CONSTANT( PARAM_PITCH_SCALE ); + BIND_CONSTANT( PARAM_ATTENUATION_MIN_DISTANCE ); + BIND_CONSTANT( PARAM_ATTENUATION_MAX_DISTANCE ); + BIND_CONSTANT( PARAM_ATTENUATION_DISTANCE_EXP ); + BIND_CONSTANT( PARAM_EMISSION_CONE_DEGREES ); + BIND_CONSTANT( PARAM_EMISSION_CONE_ATTENUATION_DB ); + BIND_CONSTANT( PARAM_MAX ); + + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/volume_db",PROPERTY_HINT_RANGE, "-80,24,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_VOLUME_DB); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/pitch_scale",PROPERTY_HINT_RANGE, "0.001,32,0.001"),_SCS("set_param"),_SCS("get_param"),PARAM_PITCH_SCALE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation/min_distance",PROPERTY_HINT_RANGE, "0.01,4096,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_ATTENUATION_MIN_DISTANCE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation/max_distance",PROPERTY_HINT_RANGE, "0.01,4096,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_ATTENUATION_MAX_DISTANCE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation/distance_exp",PROPERTY_HINT_EXP_EASING, "attenuation"),_SCS("set_param"),_SCS("get_param"),PARAM_ATTENUATION_DISTANCE_EXP); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/emission_cone/degrees",PROPERTY_HINT_RANGE, "0,180,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_EMISSION_CONE_DEGREES); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/emission_cone/attenuation_db",PROPERTY_HINT_RANGE, "-80,24,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_EMISSION_CONE_ATTENUATION_DB); + +} + + +SpatialPlayer::SpatialPlayer() { + + params[PARAM_VOLUME_DB]=0.0; + params[PARAM_PITCH_SCALE]=1.0; + params[PARAM_ATTENUATION_MIN_DISTANCE]=1; + params[PARAM_ATTENUATION_MAX_DISTANCE]=100; + params[PARAM_ATTENUATION_DISTANCE_EXP]=1.0; //linear (and not really good) + params[PARAM_EMISSION_CONE_DEGREES]=180.0; //cone disabled + params[PARAM_EMISSION_CONE_ATTENUATION_DB]=-6.0; //minus 6 db attenuation + +} + +SpatialPlayer::~SpatialPlayer() { + + +} diff --git a/scene/3d/spatial_player.h b/scene/3d/spatial_player.h new file mode 100644 index 0000000000..e11028d2c9 --- /dev/null +++ b/scene/3d/spatial_player.h @@ -0,0 +1,87 @@ +/*************************************************************************/ +/* spatial_player.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SPATIAL_PLAYER_H +#define SPATIAL_PLAYER_H + + +#include "scene/3d/spatial.h" +#include "scene/main/node.h" +#include "scene/resources/sample_library.h" +#include "servers/spatial_sound_server.h" +#include "scene/main/viewport.h" + +class SpatialPlayer : public Spatial { + + OBJ_TYPE(SpatialPlayer,Spatial); +public: + + + enum Param { + + PARAM_VOLUME_DB=SpatialSoundServer::SOURCE_PARAM_VOLUME_DB, + PARAM_PITCH_SCALE=SpatialSoundServer::SOURCE_PARAM_PITCH_SCALE, + PARAM_ATTENUATION_MIN_DISTANCE=SpatialSoundServer::SOURCE_PARAM_ATTENUATION_MIN_DISTANCE, + PARAM_ATTENUATION_MAX_DISTANCE=SpatialSoundServer::SOURCE_PARAM_ATTENUATION_MAX_DISTANCE, + PARAM_ATTENUATION_DISTANCE_EXP=SpatialSoundServer::SOURCE_PARAM_ATTENUATION_DISTANCE_EXP, + PARAM_EMISSION_CONE_DEGREES=SpatialSoundServer::SOURCE_PARAM_EMISSION_CONE_DEGREES, + PARAM_EMISSION_CONE_ATTENUATION_DB=SpatialSoundServer::SOURCE_PARAM_EMISSION_CONE_ATTENUATION_DB, + PARAM_MAX=SpatialSoundServer::SOURCE_PARAM_MAX + }; + +private: + + float params[PARAM_MAX]; + RID source_rid; + + virtual bool _can_gizmo_scale() const; + virtual RES _get_gizmo_geometry() const; + + +protected: + + _FORCE_INLINE_ RID get_source_rid() const { return source_rid; } + + void _notification(int p_what); + + static void _bind_methods(); + +public: + + void set_param( Param p_param, float p_value); + float get_param( Param p_param) const; + + + SpatialPlayer(); + ~SpatialPlayer(); + + +}; + +VARIANT_ENUM_CAST( SpatialPlayer::Param ); +#endif // SPATIAL_PLAYER_H diff --git a/scene/3d/spatial_sample_player.cpp b/scene/3d/spatial_sample_player.cpp new file mode 100644 index 0000000000..b4a5d3bc1b --- /dev/null +++ b/scene/3d/spatial_sample_player.cpp @@ -0,0 +1,229 @@ +/*************************************************************************/ +/* spatial_sample_player.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "spatial_sample_player.h" + +#include "servers/audio_server.h" +#include "camera.h" +#include "servers/spatial_sound_server.h" +#include "scene/scene_string_names.h" + +bool SpatialSamplePlayer::_set(const StringName& p_name, const Variant& p_value) { + + String name=p_name; + + if (name==SceneStringNames::get_singleton()->play_play) { + if (library.is_valid()) { + + String what=p_value; + if (what=="") + stop_all(); + else + play(what); + + played_back=what; + } + return true; + + } + + return false; +} + +bool SpatialSamplePlayer::_get(const StringName& p_name,Variant &r_ret) const { + + + String name=p_name; + + if (name==SceneStringNames::get_singleton()->play_play) { + r_ret=played_back; + return true; + } + + return false; +} + +void SpatialSamplePlayer::_get_property_list(List<PropertyInfo> *p_list) const { + + String en=""; + if (library.is_valid()) { + List<StringName> samples; + Ref<SampleLibrary> ncl=library; + ncl->get_sample_list(&samples); + for (List<StringName>::Element *E=samples.front();E;E=E->next()) { + + en+=","; + en+=E->get(); + } + } + + p_list->push_back( PropertyInfo( Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en,PROPERTY_USAGE_EDITOR)); + +} +void SpatialSamplePlayer::_notification(int p_what) { + + + switch(p_what) { + + case NOTIFICATION_ENTER_WORLD: { + + SpatialSoundServer::get_singleton()->source_set_polyphony(get_source_rid(),polyphony); + + + } break; + } + +} + +void SpatialSamplePlayer::set_sample_library(const Ref<SampleLibrary>& p_library) { + + library=p_library; +} + +Ref<SampleLibrary> SpatialSamplePlayer::get_sample_library() const { + + return library; +} + +void SpatialSamplePlayer::set_polyphony(int p_voice_count) { + + ERR_FAIL_COND(p_voice_count<0 || p_voice_count>64); + polyphony=p_voice_count; + if (get_source_rid().is_valid()) + SpatialSoundServer::get_singleton()->source_set_polyphony(get_source_rid(),polyphony); + +} + +int SpatialSamplePlayer::get_polyphony() const { + + return polyphony; +} + +SpatialSamplePlayer::VoiceID SpatialSamplePlayer::play(const String& p_sample,int p_voice) { + + if (!get_source_rid().is_valid()) + return INVALID_VOICE; + if (library.is_null()) + return INVALID_VOICE; + if (!library->has_sample(p_sample)) + return INVALID_VOICE; + Ref<Sample> sample = library->get_sample(p_sample); + float vol_change = library->sample_get_volume_db(p_sample); + float pitch_change = library->sample_get_pitch_scale(p_sample); + + VoiceID vid = SpatialSoundServer::get_singleton()->source_play_sample(get_source_rid(),sample->get_rid(),sample->get_mix_rate()*pitch_change,p_voice); + if (vol_change) + SpatialSoundServer::get_singleton()->source_voice_set_volume_scale_db(get_source_rid(),vid,vol_change); + + return vid; + + +} +//voices +void SpatialSamplePlayer::voice_set_pitch_scale(VoiceID p_voice, float p_pitch_scale) { + + if (!get_source_rid().is_valid()) + return; + + SpatialSoundServer::get_singleton()->source_voice_set_pitch_scale(get_source_rid(),p_voice,p_pitch_scale); + +} + +void SpatialSamplePlayer::voice_set_volume_scale_db(VoiceID p_voice, float p_volume_db) { + + if (!get_source_rid().is_valid()) + return; + SpatialSoundServer::get_singleton()->source_voice_set_volume_scale_db(get_source_rid(),p_voice,p_volume_db); + +} + +bool SpatialSamplePlayer::is_voice_active(VoiceID p_voice) const { + + if (!get_source_rid().is_valid()) + return false; + return SpatialSoundServer::get_singleton()->source_is_voice_active(get_source_rid(),p_voice); + +} + +void SpatialSamplePlayer::stop_voice(VoiceID p_voice) { + + if (!get_source_rid().is_valid()) + return; + SpatialSoundServer::get_singleton()->source_stop_voice(get_source_rid(),p_voice); + +} + +void SpatialSamplePlayer::stop_all() { + + if (!get_source_rid().is_valid()) + return; + + for(int i=0;i<polyphony;i++) { + + SpatialSoundServer::get_singleton()->source_stop_voice(get_source_rid(),i); + } +} + +void SpatialSamplePlayer::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_sample_library","library:SampleLibrary"),&SpatialSamplePlayer::set_sample_library); + ObjectTypeDB::bind_method(_MD("get_sample_library:SampleLibrary"),&SpatialSamplePlayer::get_sample_library); + + ObjectTypeDB::bind_method(_MD("set_polyphony","voices"),&SpatialSamplePlayer::set_polyphony); + ObjectTypeDB::bind_method(_MD("get_polyphony"),&SpatialSamplePlayer::get_polyphony); + + ObjectTypeDB::bind_method(_MD("play","sample","voice"),&SpatialSamplePlayer::play,DEFVAL(NEXT_VOICE)); + //voices,DEV + ObjectTypeDB::bind_method(_MD("voice_set_pitch_scale","voice","ratio"),&SpatialSamplePlayer::voice_set_pitch_scale); + ObjectTypeDB::bind_method(_MD("voice_set_volume_scale_db","voice","db"),&SpatialSamplePlayer::voice_set_volume_scale_db); + + ObjectTypeDB::bind_method(_MD("is_voice_active","voice"),&SpatialSamplePlayer::is_voice_active); + ObjectTypeDB::bind_method(_MD("stop_voice","voice"),&SpatialSamplePlayer::stop_voice); + ObjectTypeDB::bind_method(_MD("stop_all"),&SpatialSamplePlayer::stop_all); + + BIND_CONSTANT( INVALID_VOICE ); + BIND_CONSTANT( NEXT_VOICE ); + + ADD_PROPERTY( PropertyInfo( Variant::INT, "config/polyphony", PROPERTY_HINT_RANGE, "1,64,1"),_SCS("set_polyphony"),_SCS("get_polyphony")); + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "config/samples", PROPERTY_HINT_RESOURCE_TYPE,"SampleLibrary"),_SCS("set_sample_library"),_SCS("get_sample_library")); + + +} + + +SpatialSamplePlayer::SpatialSamplePlayer() { + + polyphony=1; + +} + +SpatialSamplePlayer::~SpatialSamplePlayer() { + + +} diff --git a/scene/3d/spatial_sample_player.h b/scene/3d/spatial_sample_player.h new file mode 100644 index 0000000000..68a0326c49 --- /dev/null +++ b/scene/3d/spatial_sample_player.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* spatial_sample_player.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SPATIAL_SAMPLE_PLAYER_H +#define SPATIAL_SAMPLE_PLAYER_H + +#include "scene/3d/spatial_player.h" +#include "scene/resources/sample_library.h" +#include "servers/spatial_sound_server.h" + +class SpatialSamplePlayer : public SpatialPlayer { + + OBJ_TYPE(SpatialSamplePlayer,SpatialPlayer); +public: + + enum { + + INVALID_VOICE=SpatialSoundServer::SOURCE_INVALID_VOICE, + NEXT_VOICE=SpatialSoundServer::SOURCE_NEXT_VOICE + }; + + typedef int VoiceID; + + +private: + + Ref<SampleLibrary> library; + int polyphony; + String played_back; +protected: + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + void _notification(int p_what); + static void _bind_methods(); + +public: + + void set_sample_library(const Ref<SampleLibrary>& p_library); + Ref<SampleLibrary> get_sample_library() const; + + void set_polyphony(int p_voice_count); + int get_polyphony() const; + + VoiceID play(const String& p_sample,int p_voice=NEXT_VOICE); + //voices + void voice_set_pitch_scale(VoiceID p_voice, float p_pitch_scale); + void voice_set_volume_scale_db(VoiceID p_voice, float p_volume_db); + + bool is_voice_active(VoiceID p_voice) const; + void stop_voice(VoiceID p_voice); + void stop_all(); + + + SpatialSamplePlayer(); + ~SpatialSamplePlayer(); + + +}; + + +#endif // SPATIAL_SAMPLE_PLAYER_H diff --git a/scene/3d/spatial_stream_player.cpp b/scene/3d/spatial_stream_player.cpp new file mode 100644 index 0000000000..25448498cb --- /dev/null +++ b/scene/3d/spatial_stream_player.cpp @@ -0,0 +1,190 @@ +/*************************************************************************/ +/* spatial_stream_player.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "spatial_stream_player.h" + + + +void SpatialStreamPlayer::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_WORLD: { + +// set_idle_process(false); //don't annoy + } break; + case NOTIFICATION_PROCESS: { + +// if (!stream.is_null()) +// stream->update(); + + } break; + case NOTIFICATION_EXIT_WORLD: { + + stop(); //wathever it may be doing, stop + } break; + } +} + + + +void SpatialStreamPlayer::set_stream(const Ref<AudioStream> &p_stream) { + + stop(); + + stream=p_stream; + if (!stream.is_null()) { + + stream->set_loop(loops); + } + + +} + +Ref<AudioStream> SpatialStreamPlayer::get_stream() const { + + return stream; +} + + +void SpatialStreamPlayer::play() { + + if (!is_inside_scene()) + return; + if (stream.is_null()) + return; + if (stream->is_playing()) + stop(); + stream->play(); + SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),stream->get_audio_stream()); + //if (stream->get_update_mode()!=AudioStream::UPDATE_NONE) + // set_idle_process(true); + +} + +void SpatialStreamPlayer::stop() { + + if (!is_inside_scene()) + return; + if (stream.is_null()) + return; + + SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),NULL); + stream->stop(); + //set_idle_process(false); +} + +bool SpatialStreamPlayer::is_playing() const { + + if (stream.is_null()) + return false; + + return stream->is_playing(); +} + +void SpatialStreamPlayer::set_loop(bool p_enable) { + + loops=p_enable; + if (stream.is_null()) + return; + stream->set_loop(loops); + +} +bool SpatialStreamPlayer::has_loop() const { + + return loops; +} + + + +String SpatialStreamPlayer::get_stream_name() const { + + if (stream.is_null()) + return "<No Stream>"; + return stream->get_name(); + +} + +int SpatialStreamPlayer::get_loop_count() const { + + if (stream.is_null()) + return 0; + return stream->get_loop_count(); + +} + +float SpatialStreamPlayer::get_pos() const { + + if (stream.is_null()) + return 0; + return stream->get_pos(); + +} +void SpatialStreamPlayer::seek_pos(float p_time) { + + if (stream.is_null()) + return; + return stream->seek_pos(p_time); + +} + +void SpatialStreamPlayer::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&SpatialStreamPlayer::set_stream); + ObjectTypeDB::bind_method(_MD("get_stream:Stream"),&SpatialStreamPlayer::get_stream); + + ObjectTypeDB::bind_method(_MD("play"),&SpatialStreamPlayer::play); + ObjectTypeDB::bind_method(_MD("stop"),&SpatialStreamPlayer::stop); + + ObjectTypeDB::bind_method(_MD("is_playing"),&SpatialStreamPlayer::is_playing); + + ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&SpatialStreamPlayer::set_loop); + ObjectTypeDB::bind_method(_MD("has_loop"),&SpatialStreamPlayer::has_loop); + + ObjectTypeDB::bind_method(_MD("get_stream_name"),&SpatialStreamPlayer::get_stream_name); + ObjectTypeDB::bind_method(_MD("get_loop_count"),&SpatialStreamPlayer::get_loop_count); + + ObjectTypeDB::bind_method(_MD("get_pos"),&SpatialStreamPlayer::get_pos); + ObjectTypeDB::bind_method(_MD("seek_pos","time"),&SpatialStreamPlayer::seek_pos); + + ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"),_SCS("get_stream") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"),_SCS("has_loop") ); + +} + + +SpatialStreamPlayer::SpatialStreamPlayer() { + + loops=false; +} + +SpatialStreamPlayer::~SpatialStreamPlayer() { + +} + + diff --git a/scene/3d/spatial_stream_player.h b/scene/3d/spatial_stream_player.h new file mode 100644 index 0000000000..6b73a8ad1b --- /dev/null +++ b/scene/3d/spatial_stream_player.h @@ -0,0 +1,72 @@ +/*************************************************************************/ +/* spatial_stream_player.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SPATIAL_STREAM_PLAYER_H +#define SPATIAL_STREAM_PLAYER_H + +#include "scene/resources/audio_stream.h" +#include "scene/3d/spatial_player.h" + + +class SpatialStreamPlayer : public SpatialPlayer { + + OBJ_TYPE(SpatialStreamPlayer,SpatialPlayer); + + Ref<AudioStream> stream; + bool loops; +protected: + + void _notification(int p_what); + + static void _bind_methods(); +public: + + void set_stream(const Ref<AudioStream> &p_stream); + Ref<AudioStream> get_stream() const; + + void play(); + void stop(); + bool is_playing() const; + + void set_loop(bool p_enable); + bool has_loop() const; + + + String get_stream_name() const; + int get_loop_count() const; + + + float get_pos() const; + void seek_pos(float p_time); + + + SpatialStreamPlayer(); + ~SpatialStreamPlayer(); +}; + +#endif // SPATIAL_STREAM_PLAYER_H diff --git a/scene/3d/test_cube.cpp b/scene/3d/test_cube.cpp new file mode 100644 index 0000000000..265263a760 --- /dev/null +++ b/scene/3d/test_cube.cpp @@ -0,0 +1,53 @@ +/*************************************************************************/ +/* test_cube.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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_cube.h" +#include "servers/visual_server.h" + + + +AABB TestCube::get_aabb() const { + + return AABB( Vector3(-1,-1,-1), Vector3(2, 2, 2 ) ); +} +DVector<Face3> TestCube::get_faces(uint32_t p_usage_flags) const { + + return DVector<Face3>(); +} + + +TestCube::TestCube() { + + set_base(VisualServer::get_singleton()->get_test_cube()); +} + + +TestCube::~TestCube() { +} + + diff --git a/scene/3d/test_cube.h b/scene/3d/test_cube.h new file mode 100644 index 0000000000..8a5b566f1f --- /dev/null +++ b/scene/3d/test_cube.h @@ -0,0 +1,57 @@ +/*************************************************************************/ +/* test_cube.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef TEST_CUBE_H +#define TEST_CUBE_H + + +#include "scene/3d/visual_instance.h" +#include "rid.h" + + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class TestCube : public GeometryInstance { + + OBJ_TYPE( TestCube, GeometryInstance ); + + RID instance; + + +public: + + virtual AABB get_aabb() const; + virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; + + TestCube(); + ~TestCube(); + +}; + +#endif diff --git a/scene/3d/visibility_notifier.cpp b/scene/3d/visibility_notifier.cpp new file mode 100644 index 0000000000..da01827c49 --- /dev/null +++ b/scene/3d/visibility_notifier.cpp @@ -0,0 +1,314 @@ +/*************************************************************************/ +/* visibility_notifier.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "visibility_notifier.h" + +#include "scene/scene_string_names.h" +#include "scene/3d/physics_body.h" +#include "scene/animation/animation_player.h" +#include "scene/scene_string_names.h" + +void VisibilityNotifier::_enter_camera(Camera* p_camera) { + + ERR_FAIL_COND(cameras.has(p_camera)); + cameras.insert(p_camera); + if (cameras.size()==1) { + emit_signal(SceneStringNames::get_singleton()->enter_screen); + _screen_enter(); + } + emit_signal(SceneStringNames::get_singleton()->enter_camera,p_camera); + +} + +void VisibilityNotifier::_exit_camera(Camera* p_camera){ + + ERR_FAIL_COND(!cameras.has(p_camera)); + cameras.erase(p_camera); + + emit_signal(SceneStringNames::get_singleton()->exit_camera,p_camera); + if (cameras.size()==0) { + emit_signal(SceneStringNames::get_singleton()->exit_screen); + + _screen_exit(); + + } +} + + +void VisibilityNotifier::set_aabb(const AABB& p_aabb){ + + if (aabb==p_aabb) + return; + aabb=p_aabb; + + if (is_inside_world()) { + get_world()->_update_notifier(this,get_global_transform().xform(aabb)); + } + + _change_notify("aabb"); + update_gizmo(); +} + +AABB VisibilityNotifier::get_aabb() const{ + + return aabb; +} + + +void VisibilityNotifier::_notification(int p_what) { + + + switch(p_what) { + case NOTIFICATION_ENTER_WORLD: { + + + get_world()->_register_notifier(this,get_global_transform().xform(aabb)); + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + + get_world()->_update_notifier(this,get_global_transform().xform(aabb)); + } break; + case NOTIFICATION_EXIT_WORLD: { + + get_world()->_remove_notifier(this); + } break; + } +} + + +bool VisibilityNotifier::is_on_screen() const { + + return cameras.size()!=0; +} + +void VisibilityNotifier::_bind_methods(){ + + ObjectTypeDB::bind_method(_MD("set_aabb","rect"),&VisibilityNotifier::set_aabb); + ObjectTypeDB::bind_method(_MD("get_aabb"),&VisibilityNotifier::get_aabb); + ObjectTypeDB::bind_method(_MD("is_on_screen"),&VisibilityNotifier::is_on_screen); + + ADD_PROPERTY( PropertyInfo(Variant::_AABB,"aabb"),_SCS("set_aabb"),_SCS("get_aabb")); + + ADD_SIGNAL( MethodInfo("enter_camera",PropertyInfo(Variant::OBJECT,"camera",PROPERTY_HINT_RESOURCE_TYPE,"Camera")) ); + ADD_SIGNAL( MethodInfo("exit_camera",PropertyInfo(Variant::OBJECT,"camera",PROPERTY_HINT_RESOURCE_TYPE,"Camera")) ); + ADD_SIGNAL( MethodInfo("enter_screen")); + ADD_SIGNAL( MethodInfo("exit_screen")); +} + + +VisibilityNotifier::VisibilityNotifier() { + + aabb=AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); + +} + + + + + +////////////////////////////////////// + + +void VisibilityEnabler::_screen_enter() { + + + for(Map<Node*,Variant>::Element *E=nodes.front();E;E=E->next()) { + + _change_node_state(E->key(),true); + } + + visible=true; +} + +void VisibilityEnabler::_screen_exit() { + + for(Map<Node*,Variant>::Element *E=nodes.front();E;E=E->next()) { + + _change_node_state(E->key(),false); + } + + visible=false; +} + +void VisibilityEnabler::_find_nodes(Node* p_node) { + + + bool add=false; + Variant meta; + + if (enabler[ENABLER_FREEZE_BODIES]) { + + RigidBody *rb = p_node->cast_to<RigidBody>(); + if (rb && ((rb->get_mode()==RigidBody::MODE_CHARACTER || (rb->get_mode()==RigidBody::MODE_RIGID && !rb->is_able_to_sleep())))) { + + + add=true; + meta=rb->get_mode(); + } + } + + if (enabler[ENABLER_PAUSE_ANIMATIONS]) { + + AnimationPlayer *ap = p_node->cast_to<AnimationPlayer>(); + if (ap) { + add=true; + } + } + + if (add) { + + p_node->connect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed",varray(p_node),CONNECT_ONESHOT); + nodes[p_node]=meta; + _change_node_state(p_node,false); + } + + for(int i=0;i<p_node->get_child_count();i++) { + Node *c = p_node->get_child(i); + if (c->get_filename()!=String()) + continue; //skip, instance + + _find_nodes(c); + } + +} + +void VisibilityEnabler::_notification(int p_what){ + + if (p_what==NOTIFICATION_ENTER_SCENE) { + + if (get_scene()->is_editor_hint()) + return; + + + Node *from = this; + //find where current scene starts + while(from->get_parent() && from->get_filename()==String()) + from=from->get_parent(); + + _find_nodes(from); + + } + + if (p_what==NOTIFICATION_EXIT_SCENE) { + + if (get_scene()->is_editor_hint()) + return; + + + Node *from = this; + //find where current scene starts + + for (Map<Node*,Variant>::Element *E=nodes.front();E;E=E->next()) { + + if (!visible) + _change_node_state(E->key(),true); + E->key()->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed"); + } + + nodes.clear(); + + } +} + +void VisibilityEnabler::_change_node_state(Node* p_node,bool p_enabled) { + + ERR_FAIL_COND(!nodes.has(p_node)); + + { + RigidBody *rb = p_node->cast_to<RigidBody>(); + if (rb) { + + if (p_enabled) { + RigidBody::Mode mode = RigidBody::Mode(nodes[p_node].operator int()); + //rb->set_mode(mode); + rb->set_active(true); + } else { + //rb->set_mode(RigidBody::MODE_STATIC); + rb->set_active(false); + } + } + } + + { + AnimationPlayer *ap=p_node->cast_to<AnimationPlayer>(); + + if (ap) { + + ap->set_active(p_enabled); + } + } + +} + + +void VisibilityEnabler::_node_removed(Node* p_node) { + + if (!visible) + _change_node_state(p_node,true); + p_node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed"); + nodes.erase(p_node); + +} + +void VisibilityEnabler::_bind_methods(){ + + ObjectTypeDB::bind_method(_MD("set_enabler","enabler","enabled"),&VisibilityEnabler::set_enabler); + ObjectTypeDB::bind_method(_MD("is_enabler_enabled","enabler"),&VisibilityEnabler::is_enabler_enabled); + ObjectTypeDB::bind_method(_MD("_node_removed"),&VisibilityEnabler::_node_removed); + + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_animations"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_ANIMATIONS ); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/freeze_bodies"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_FREEZE_BODIES); + + BIND_CONSTANT( ENABLER_FREEZE_BODIES ); + BIND_CONSTANT( ENABLER_PAUSE_ANIMATIONS ); + BIND_CONSTANT( ENABLER_MAX); +} + +void VisibilityEnabler::set_enabler(Enabler p_enabler,bool p_enable){ + + ERR_FAIL_INDEX(p_enabler,ENABLER_MAX); + enabler[p_enabler]=p_enable; + +} +bool VisibilityEnabler::is_enabler_enabled(Enabler p_enabler) const{ + + ERR_FAIL_INDEX_V(p_enabler,ENABLER_MAX,false); + return enabler[p_enabler]; + +} + +VisibilityEnabler::VisibilityEnabler() { + + for(int i=0;i<ENABLER_MAX;i++) + enabler[i]=true; + + visible=false; + +} + diff --git a/scene/3d/visibility_notifier.h b/scene/3d/visibility_notifier.h new file mode 100644 index 0000000000..52acd0ba2c --- /dev/null +++ b/scene/3d/visibility_notifier.h @@ -0,0 +1,106 @@ +/*************************************************************************/ +/* visibility_notifier.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef VISIBILITY_NOTIFIER_H +#define VISIBILITY_NOTIFIER_H + +#include "scene/3d/spatial.h" + +class Camera; +class VisibilityNotifier : public Spatial { + + OBJ_TYPE(VisibilityNotifier,Spatial); + + Set<Camera*> cameras; + + AABB aabb; + +protected: + + virtual void _screen_enter() {} + virtual void _screen_exit() {} + + void _notification(int p_what); + static void _bind_methods(); +friend class SpatialIndexer; + + void _enter_camera(Camera* p_camera); + void _exit_camera(Camera* p_camera); + +public: + + void set_aabb(const AABB& p_aabb); + AABB get_aabb() const; + bool is_on_screen() const; + + VisibilityNotifier(); +}; + + +class VisibilityEnabler : public VisibilityNotifier { + + OBJ_TYPE(VisibilityEnabler,VisibilityNotifier); +public: + + enum Enabler { + ENABLER_PAUSE_ANIMATIONS, + ENABLER_FREEZE_BODIES, + ENABLER_MAX + }; + +protected: + + virtual void _screen_enter(); + virtual void _screen_exit(); + + bool visible; + + void _find_nodes(Node* p_node); + + Map<Node*,Variant> nodes; + void _node_removed(Node* p_node); + bool enabler[ENABLER_MAX]; + + void _change_node_state(Node* p_node,bool p_enabled); + + void _notification(int p_what); + static void _bind_methods(); + +public: + + void set_enabler(Enabler p_enabler,bool p_enable); + bool is_enabler_enabled(Enabler p_enabler) const; + + VisibilityEnabler(); + +}; + +VARIANT_ENUM_CAST(VisibilityEnabler::Enabler); + + +#endif // VISIBILITY_NOTIFIER_H diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp new file mode 100644 index 0000000000..9419996187 --- /dev/null +++ b/scene/3d/visual_instance.cpp @@ -0,0 +1,260 @@ +/*************************************************************************/ +/* visual_instance.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "visual_instance.h" + +#include "servers/visual_server.h" +#include "room_instance.h" +#include "scene/scene_string_names.h" + +#include "skeleton.h" + +AABB VisualInstance::get_transformed_aabb() const { + + return get_global_transform().xform( get_aabb() ); +} + + + +void VisualInstance::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_WORLD: { + + // CHECK ROOM + Spatial * parent = get_parent_spatial(); + Room *room=NULL; + + while(parent) { + + room = parent->cast_to<Room>(); + if (room) + break; + else + parent=parent->get_parent_spatial(); + } + + + if (room) { + + VisualServer::get_singleton()->instance_set_room(instance,room->get_instance()); + } + // CHECK SKELETON + Skeleton *skeleton=get_parent()?get_parent()->cast_to<Skeleton>():NULL; + if (skeleton) + VisualServer::get_singleton()->instance_attach_skeleton( instance, skeleton->get_skeleton() ); + + VisualServer::get_singleton()->instance_set_scenario( instance, get_world()->get_scenario() ); + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + Transform gt = get_global_transform(); + VisualServer::get_singleton()->instance_set_transform(instance,gt); + } break; + case NOTIFICATION_EXIT_WORLD: { + + VisualServer::get_singleton()->instance_set_scenario( instance, RID() ); + VisualServer::get_singleton()->instance_set_room(instance,RID()); + VisualServer::get_singleton()->instance_attach_skeleton( instance, RID() ); + + + } break; + } +} + +RID VisualInstance::get_instance() const { + + return instance; +} + +RID VisualInstance::_get_visual_instance_rid() const { + + return instance; +} + +void VisualInstance::set_layer_mask(uint32_t p_mask) { + + layers=p_mask; + VisualServer::get_singleton()->instance_set_layer_mask(instance,p_mask); +} + +uint32_t VisualInstance::get_layer_mask() const { + + return layers; +} + + +void VisualInstance::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_get_visual_instance_rid"),&VisualInstance::_get_visual_instance_rid); + ObjectTypeDB::bind_method(_MD("set_base","base"), &VisualInstance::set_base); + ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"), &VisualInstance::set_layer_mask); + ObjectTypeDB::bind_method(_MD("get_layer_mask"), &VisualInstance::get_layer_mask); + + ADD_PROPERTY( PropertyInfo( Variant::INT, "layers",PROPERTY_HINT_ALL_FLAGS), _SCS("set_layer_mask"), _SCS("get_layer_mask")); + + +} + + +void VisualInstance::set_base(const RID& p_base) { + + VisualServer::get_singleton()->instance_set_base(instance,p_base); +} + + +VisualInstance::VisualInstance() +{ + + instance = VisualServer::get_singleton()->instance_create(); + VisualServer::get_singleton()->instance_attach_object_instance_ID( instance, get_instance_ID() ); + layers=1; +} + + +VisualInstance::~VisualInstance() { + + VisualServer::get_singleton()->free(instance); +} + + + + +void GeometryInstance::set_material_override(const Ref<Material>& p_material) { + + material_override=p_material; + VS::get_singleton()->instance_geometry_set_material_override(get_instance(),p_material.is_valid() ? p_material->get_rid() : RID()); +} + +Ref<Material> GeometryInstance::get_material_override() const{ + + return material_override; +} + + + +void GeometryInstance::set_draw_range_begin(float p_dist){ + + draw_begin=p_dist; + VS::get_singleton()->instance_geometry_set_draw_range(get_instance(),draw_begin,draw_end); +} + +float GeometryInstance::get_draw_range_begin() const{ + + return draw_begin; +} + + +void GeometryInstance::set_draw_range_end(float p_dist) { + + draw_end=p_dist; + VS::get_singleton()->instance_geometry_set_draw_range(get_instance(),draw_begin,draw_end); + +} + +float GeometryInstance::get_draw_range_end() const { + + return draw_end; +} + +void GeometryInstance::set_flag(Flags p_flag,bool p_value) { + + ERR_FAIL_INDEX(p_flag,FLAG_MAX); + if (flags[p_flag]==p_value) + return; + + flags[p_flag]=p_value; + VS::get_singleton()->instance_geometry_set_flag(get_instance(),(VS::InstanceFlags)p_flag,p_value); + if (p_flag==FLAG_VISIBLE) { + _change_notify("geometry/visible"); + emit_signal(SceneStringNames::get_singleton()->visibility_changed); + } + + +} + +bool GeometryInstance::get_flag(Flags p_flag) const{ + + ERR_FAIL_INDEX_V(p_flag,FLAG_MAX,false); + return flags[p_flag]; + +} + + +void GeometryInstance::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_material_override","material"), &GeometryInstance::set_material_override); + ObjectTypeDB::bind_method(_MD("get_material_override"), &GeometryInstance::get_material_override); + + ObjectTypeDB::bind_method(_MD("set_flag","flag","value"), &GeometryInstance::set_flag); + ObjectTypeDB::bind_method(_MD("get_flag","flag"), &GeometryInstance::get_flag); + + ObjectTypeDB::bind_method(_MD("set_draw_range_begin","mode"), &GeometryInstance::set_draw_range_begin); + ObjectTypeDB::bind_method(_MD("get_draw_range_begin"), &GeometryInstance::get_draw_range_begin); + + ObjectTypeDB::bind_method(_MD("set_draw_range_end","mode"), &GeometryInstance::set_draw_range_end); + ObjectTypeDB::bind_method(_MD("get_draw_range_end"), &GeometryInstance::get_draw_range_end); + + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE); + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "geometry/material_override",PROPERTY_HINT_RESOURCE_TYPE,"Material"), _SCS("set_material_override"), _SCS("get_material_override")); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/cast_shadow"), _SCS("set_flag"), _SCS("get_flag"),FLAG_CAST_SHADOW); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/receive_shadows"), _SCS("set_flag"), _SCS("get_flag"),FLAG_RECEIVE_SHADOWS); + ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_begin",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_begin"), _SCS("get_draw_range_begin")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_end",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_end"), _SCS("get_draw_range_end")); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard_y"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD_FIX_Y); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible_in_all_rooms"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE_IN_ALL_ROOMS); + + ADD_SIGNAL( MethodInfo("visibility_changed")); + + BIND_CONSTANT(FLAG_VISIBLE ); + BIND_CONSTANT(FLAG_CAST_SHADOW ); + BIND_CONSTANT(FLAG_RECEIVE_SHADOWS ); + BIND_CONSTANT(FLAG_BILLBOARD ); + BIND_CONSTANT(FLAG_BILLBOARD_FIX_Y ); + BIND_CONSTANT(FLAG_DEPH_SCALE ); + BIND_CONSTANT(FLAG_VISIBLE_IN_ALL_ROOMS ); + BIND_CONSTANT(FLAG_MAX ); + +} + +GeometryInstance::GeometryInstance() { + draw_begin=0; + draw_end=0; + flags[FLAG_VISIBLE]=true; + flags[FLAG_CAST_SHADOW]=true; + flags[FLAG_RECEIVE_SHADOWS]=true; + flags[FLAG_BILLBOARD]=false; + flags[FLAG_BILLBOARD_FIX_Y]=false; + flags[FLAG_DEPH_SCALE]=false; + flags[FLAG_VISIBLE_IN_ALL_ROOMS]=false; + +} diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h new file mode 100644 index 0000000000..4e652912c6 --- /dev/null +++ b/scene/3d/visual_instance.h @@ -0,0 +1,126 @@ +/*************************************************************************/ +/* visual_instance.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef VISUAL_INSTANCE_H +#define VISUAL_INSTANCE_H + +#include "scene/3d/spatial.h" +#include "face3.h" +#include "rid.h" +#include "scene/resources/material.h" +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class VisualInstance : public Spatial { + + OBJ_TYPE( VisualInstance, Spatial ); + OBJ_CATEGORY("3D Visual Nodes"); + + RID instance; + uint32_t layers; + + + RID _get_visual_instance_rid() const; + +protected: + + + void _notification(int p_what); + static void _bind_methods(); +public: + + enum GetFacesFlags { + FACES_SOLID=1, // solid geometry + FACES_ENCLOSING=2, + FACES_DYNAMIC=4 // dynamic object geometry + + }; + + RID get_instance() const; + virtual AABB get_aabb() const=0; + virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const=0; + + virtual AABB get_transformed_aabb() const; // helper + + void set_base(const RID& p_base); + + void set_layer_mask(uint32_t p_mask); + uint32_t get_layer_mask() const; + + + VisualInstance(); + ~VisualInstance(); + +}; + +class GeometryInstance : public VisualInstance { + + OBJ_TYPE( GeometryInstance, VisualInstance ); +public: + + enum Flags { + FLAG_VISIBLE=VS::INSTANCE_FLAG_VISIBLE, + FLAG_CAST_SHADOW=VS::INSTANCE_FLAG_CAST_SHADOW, + FLAG_RECEIVE_SHADOWS=VS::INSTANCE_FLAG_RECEIVE_SHADOWS, + FLAG_BILLBOARD=VS::INSTANCE_FLAG_BILLBOARD, + FLAG_BILLBOARD_FIX_Y=VS::INSTANCE_FLAG_BILLBOARD_FIX_Y, + FLAG_DEPH_SCALE=VS::INSTANCE_FLAG_DEPH_SCALE, + FLAG_VISIBLE_IN_ALL_ROOMS=VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, + FLAG_MAX=VS::INSTANCE_FLAG_MAX, + }; + + +private: + + bool flags[FLAG_MAX]; + Ref<Material> material_override; + float draw_begin; + float draw_end; +protected: + + static void _bind_methods(); +public: + + void set_flag(Flags p_flag,bool p_value); + bool get_flag(Flags p_flag) const; + + void set_draw_range_begin(float p_dist); + float get_draw_range_begin() const; + + void set_draw_range_end(float p_dist); + float get_draw_range_end() const; + + void set_material_override(const Ref<Material>& p_material); + Ref<Material> get_material_override() const; + + GeometryInstance(); +}; + +VARIANT_ENUM_CAST( GeometryInstance::Flags ); + +#endif |