GODOT IS OPEN SOURCE

This commit is contained in:
Juan Linietsky
2014-02-09 22:10:30 -03:00
parent 0e49da1687
commit 0b806ee0fc
3138 changed files with 1294441 additions and 0 deletions

7
scene/2d/SCsub Normal file
View File

@ -0,0 +1,7 @@
Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
Export('env')

View File

@ -0,0 +1,352 @@
/*************************************************************************/
/* animated_sprite.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 "animated_sprite.h"
void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) {
set_offset(p_pivot);
}
Point2 AnimatedSprite::edit_get_pivot() const {
return get_offset();
}
bool AnimatedSprite::edit_has_pivot() const {
return true;
}
void SpriteFrames::add_frame(const Ref<Texture>& p_frame,int p_at_pos) {
if (p_at_pos>=0 && p_at_pos<frames.size())
frames.insert(p_at_pos,p_frame);
else
frames.push_back(p_frame);
emit_changed();
}
int SpriteFrames::get_frame_count() const {
return frames.size();
}
void SpriteFrames::remove_frame(int p_idx) {
frames.remove(p_idx);
emit_changed();
}
void SpriteFrames::clear() {
frames.clear();
emit_changed();
}
Array SpriteFrames::_get_frames() const {
Array arr;
arr.resize(frames.size());
for(int i=0;i<frames.size();i++)
arr[i]=frames[i];
return arr;
}
void SpriteFrames::_set_frames(const Array& p_frames) {
frames.resize(p_frames.size());
for(int i=0;i<frames.size();i++)
frames[i]=p_frames[i];
}
void SpriteFrames::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_frame","frame","atpos"),&SpriteFrames::add_frame,DEFVAL(-1));
ObjectTypeDB::bind_method(_MD("get_frame_count"),&SpriteFrames::get_frame_count);
ObjectTypeDB::bind_method(_MD("get_frame","idx"),&SpriteFrames::get_frame);
ObjectTypeDB::bind_method(_MD("set_frame","idx","txt"),&SpriteFrames::set_frame);
ObjectTypeDB::bind_method(_MD("remove_frame","idx"),&SpriteFrames::remove_frame);
ObjectTypeDB::bind_method(_MD("clear"),&SpriteFrames::clear);
ObjectTypeDB::bind_method(_MD("_set_frames"),&SpriteFrames::_set_frames);
ObjectTypeDB::bind_method(_MD("_get_frames"),&SpriteFrames::_get_frames);
ADD_PROPERTYNZ( PropertyInfo(Variant::ARRAY,"frames",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_frames"),_SCS("_get_frames"));
}
SpriteFrames::SpriteFrames() {
}
//////////////////////////
void AnimatedSprite::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
if (frames.is_null())
return;
if (frame<0 || frame>=frames->get_frame_count())
return;
Ref<Texture> texture = frames->get_frame(frame);
if (texture.is_null())
return;
//print_line("DECIDED TO DRAW");
RID ci = get_canvas_item();
/*
texture->draw(ci,Point2());
break;
*/
Size2i s;
s = texture->get_size();
Point2i ofs=offset;
if (centered)
ofs-=s/2;
Rect2i dst_rect(ofs,s);
if (hflip)
dst_rect.size.x=-dst_rect.size.x;
if (vflip)
dst_rect.size.y=-dst_rect.size.y;
texture->draw_rect(ci,dst_rect,false,modulate);
// VisualServer::get_singleton()->canvas_item_add_texture_rect_region(ci,dst_rect,texture->get_rid(),src_rect,modulate);
} break;
}
}
void AnimatedSprite::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
if (frames.is_valid())
frames->disconnect("changed",this,"_res_changed");
frames=p_frames;
if (frames.is_valid())
frames->connect("changed",this,"_res_changed");
if (!frames.is_valid()) {
frame=0;
} else {
set_frame(frame);
}
update();
}
Ref<SpriteFrames> AnimatedSprite::get_sprite_frames() const {
return frames;
}
void AnimatedSprite::set_frame(int p_frame) {
if (!frames.is_valid()) {
return;
}
if (p_frame>=frames->get_frame_count())
p_frame=frames->get_frame_count()-1;
if (p_frame<0)
p_frame=0;
if (frame==p_frame)
return;
frame=p_frame;
update();
_change_notify("frame");
}
int AnimatedSprite::get_frame() const {
return frame;
}
void AnimatedSprite::set_centered(bool p_center) {
centered=p_center;
update();
item_rect_changed();
}
bool AnimatedSprite::is_centered() const {
return centered;
}
void AnimatedSprite::set_offset(const Point2& p_offset) {
offset=p_offset;
update();
item_rect_changed();
}
Point2 AnimatedSprite::get_offset() const {
return offset;
}
void AnimatedSprite::set_flip_h(bool p_flip) {
hflip=p_flip;
update();
}
bool AnimatedSprite::is_flipped_h() const {
return hflip;
}
void AnimatedSprite::set_flip_v(bool p_flip) {
vflip=p_flip;
update();
}
bool AnimatedSprite::is_flipped_v() const {
return vflip;
}
void AnimatedSprite::set_modulate(const Color& p_color) {
modulate=p_color;
update();
}
Color AnimatedSprite::get_modulate() const{
return modulate;
}
Rect2 AnimatedSprite::get_item_rect() const {
if (!frames.is_valid() || !frames->get_frame_count() || frame<0 || frame>=frames->get_frame_count()) {
return Node2D::get_item_rect();
}
Ref<Texture> t = frames->get_frame(frame);
if (t.is_null())
return Node2D::get_item_rect();
Size2i s = t->get_size();
Point2i ofs=offset;
if (centered)
ofs-=s/2;
if (s==Size2(0,0))
s=Size2(1,1);
return Rect2(ofs,s);
}
void AnimatedSprite::_res_changed() {
set_frame(frame);
update();
}
void AnimatedSprite::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_sprite_frames","sprite_frames:SpriteFrames"),&AnimatedSprite::set_sprite_frames);
ObjectTypeDB::bind_method(_MD("get_sprite_frames:SpriteFrames"),&AnimatedSprite::get_sprite_frames);
ObjectTypeDB::bind_method(_MD("set_centered","centered"),&AnimatedSprite::set_centered);
ObjectTypeDB::bind_method(_MD("is_centered"),&AnimatedSprite::is_centered);
ObjectTypeDB::bind_method(_MD("set_offset","offset"),&AnimatedSprite::set_offset);
ObjectTypeDB::bind_method(_MD("get_offset"),&AnimatedSprite::get_offset);
ObjectTypeDB::bind_method(_MD("set_flip_h","flip_h"),&AnimatedSprite::set_flip_h);
ObjectTypeDB::bind_method(_MD("is_flipped_h"),&AnimatedSprite::is_flipped_h);
ObjectTypeDB::bind_method(_MD("set_flip_v","flip_v"),&AnimatedSprite::set_flip_v);
ObjectTypeDB::bind_method(_MD("is_flipped_v"),&AnimatedSprite::is_flipped_v);
ObjectTypeDB::bind_method(_MD("set_frame","frame"),&AnimatedSprite::set_frame);
ObjectTypeDB::bind_method(_MD("get_frame"),&AnimatedSprite::get_frame);
ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&AnimatedSprite::set_modulate);
ObjectTypeDB::bind_method(_MD("get_modulate"),&AnimatedSprite::get_modulate);
ObjectTypeDB::bind_method(_MD("_res_changed"),&AnimatedSprite::_res_changed);
ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "frames",PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames"));
ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
}
AnimatedSprite::AnimatedSprite() {
centered=true;
hflip=false;
vflip=false;
frame=0;
modulate=Color(1,1,1,1);
}

119
scene/2d/animated_sprite.h Normal file
View File

@ -0,0 +1,119 @@
/*************************************************************************/
/* animated_sprite.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 ANIMATED_SPRITE_H
#define ANIMATED_SPRITE_H
#include "scene/2d/node_2d.h"
#include "scene/resources/texture.h"
class SpriteFrames : public Resource {
OBJ_TYPE(SpriteFrames,Resource);
Vector< Ref<Texture> > frames;
Array _get_frames() const;
void _set_frames(const Array& p_frames);
protected:
static void _bind_methods();
public:
void add_frame(const Ref<Texture>& p_frame,int p_at_pos=-1);
int get_frame_count() const;
_FORCE_INLINE_ Ref<Texture> get_frame(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,frames.size(),Ref<Texture>()); return frames[p_idx]; }
void set_frame(int p_idx,const Ref<Texture>& p_frame){ ERR_FAIL_INDEX(p_idx,frames.size()); frames[p_idx]=p_frame; }
void remove_frame(int p_idx);
void clear();
SpriteFrames();
};
class AnimatedSprite : public Node2D {
OBJ_TYPE(AnimatedSprite,Node2D);
Ref<SpriteFrames> frames;
int frame;
bool centered;
Point2 offset;
bool hflip;
bool vflip;
Color modulate;
void _res_changed();
protected:
static void _bind_methods();
void _notification(int p_what);
public:
virtual void edit_set_pivot(const Point2& p_pivot);
virtual Point2 edit_get_pivot() const;
virtual bool edit_has_pivot() const;
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
void set_frame(int p_frame);
int get_frame() const;
void set_centered(bool p_center);
bool is_centered() const;
void set_offset(const Point2& p_offset);
Point2 get_offset() const;
void set_flip_h(bool p_flip);
bool is_flipped_h() const;
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
void set_modulate(const Color& p_color);
Color get_modulate() const;
virtual Rect2 get_item_rect() const;
AnimatedSprite();
};
#endif // ANIMATED_SPRITE_H

326
scene/2d/area_2d.cpp Normal file
View File

@ -0,0 +1,326 @@
/*************************************************************************/
/* area_2d.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_2d.h"
#include "scene/scene_string_names.h"
#include "servers/physics_2d_server.h"
void Area2D::set_space_override_mode(SpaceOverride p_mode) {
space_override=p_mode;
Physics2DServer::get_singleton()->area_set_space_override_mode(get_rid(),Physics2DServer::AreaSpaceOverrideMode(p_mode));
}
Area2D::SpaceOverride Area2D::get_space_override_mode() const{
return space_override;
}
void Area2D::set_gravity_is_point(bool p_enabled){
gravity_is_point=p_enabled;
Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_GRAVITY_IS_POINT,p_enabled);
}
bool Area2D::is_gravity_a_point() const{
return gravity_is_point;
}
void Area2D::set_gravity_vector(const Vector2& p_vec){
gravity_vec=p_vec;
Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_GRAVITY_VECTOR,p_vec);
}
Vector2 Area2D::get_gravity_vector() const{
return gravity_vec;
}
void Area2D::set_gravity(real_t p_gravity){
gravity=p_gravity;
Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_GRAVITY,p_gravity);
}
real_t Area2D::get_gravity() const{
return gravity;
}
void Area2D::set_density(real_t p_density){
density=p_density;
Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_DENSITY,p_density);
}
real_t Area2D::get_density() const{
return density;
}
void Area2D::set_priority(real_t p_priority){
priority=p_priority;
Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_PRIORITY,p_priority);
}
real_t Area2D::get_priority() const{
return priority;
}
void Area2D::_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 Area2D::_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 Area2D::_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==Physics2DServer::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 Area2D::_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 Area2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_EXIT_SCENE: {
_clear_monitoring();
} break;
}
}
void Area2D::set_enable_monitoring(bool p_enable) {
if (p_enable==monitoring)
return;
monitoring=p_enable;
if (monitoring) {
Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout");
} else {
Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName());
_clear_monitoring();
}
}
bool Area2D::is_monitoring_enabled() const {
return monitoring;
}
void Area2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_body_enter_scene","id"),&Area2D::_body_enter_scene);
ObjectTypeDB::bind_method(_MD("_body_exit_scene","id"),&Area2D::_body_exit_scene);
ObjectTypeDB::bind_method(_MD("set_space_override_mode","enable"),&Area2D::set_space_override_mode);
ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area2D::get_space_override_mode);
ObjectTypeDB::bind_method(_MD("set_gravity_is_point","enable"),&Area2D::set_gravity_is_point);
ObjectTypeDB::bind_method(_MD("is_gravity_a_point"),&Area2D::is_gravity_a_point);
ObjectTypeDB::bind_method(_MD("set_gravity_vector","vector"),&Area2D::set_gravity_vector);
ObjectTypeDB::bind_method(_MD("get_gravity_vector"),&Area2D::get_gravity_vector);
ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&Area2D::set_gravity);
ObjectTypeDB::bind_method(_MD("get_gravity"),&Area2D::get_gravity);
ObjectTypeDB::bind_method(_MD("set_density","density"),&Area2D::set_density);
ObjectTypeDB::bind_method(_MD("get_density"),&Area2D::get_density);
ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area2D::set_priority);
ObjectTypeDB::bind_method(_MD("get_priority"),&Area2D::get_priority);
ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area2D::set_enable_monitoring);
ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area2D::is_monitoring_enabled);
ObjectTypeDB::bind_method(_MD("_body_inout"),&Area2D::_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_PROPERTYNZ( 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::VECTOR2,"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_PROPERTYNZ( 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"));
}
Area2D::Area2D() : CollisionObject2D(Physics2DServer::get_singleton()->area_create(),true) {
space_override=SPACE_OVERRIDE_DISABLED;
set_gravity(98);;
set_gravity_vector(Vector2(0,1));
gravity_is_point=false;
density=0.1;
priority=0;
monitoring=false;
}
Area2D::~Area2D() {
}

122
scene/2d/area_2d.h Normal file
View File

@ -0,0 +1,122 @@
/*************************************************************************/
/* area_2d.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_2D_H
#define AREA_2D_H
#include "scene/2d/collision_object_2d.h"
#include "vset.h"
class Area2D : public CollisionObject2D {
OBJ_TYPE( Area2D, CollisionObject2D );
public:
enum SpaceOverride {
SPACE_OVERRIDE_DISABLED,
SPACE_OVERRIDE_COMBINE,
SPACE_OVERRIDE_REPLACE
};
private:
SpaceOverride space_override;
Vector2 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 Vector2& p_vec);
Vector2 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;
Area2D();
~Area2D();
};
VARIANT_ENUM_CAST(Area2D::SpaceOverride);
#endif // AREA_2D_H

484
scene/2d/camera_2d.cpp Normal file
View File

@ -0,0 +1,484 @@
/*************************************************************************/
/* camera_2d.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_2d.h"
#include "scene/scene_string_names.h"
#include "servers/visual_server.h"
void Camera2D::_update_scroll() {
if (!is_inside_scene())
return;
if (get_scene()->is_editor_hint()) {
update(); //will just be drawn
return;
}
if (current) {
Matrix32 xform = get_camera_transform();
RID vp = viewport->get_viewport();
if (viewport) {
viewport->set_canvas_transform( xform );
}
get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,group_name,"_camera_moved",xform);
};
}
void Camera2D::set_zoom(const Vector2 &p_zoom) {
zoom = p_zoom;
_update_scroll();
};
Vector2 Camera2D::get_zoom() const {
return zoom;
};
Matrix32 Camera2D::get_camera_transform() {
if (!get_scene())
return Matrix32();
Size2 screen_size = get_viewport_rect().size;
screen_size=get_viewport_rect().size;
Point2 new_camera_pos = get_global_transform().get_origin();
Point2 ret_camera_pos;
if (!first) {
if (centered) {
if (h_drag_enabled) {
camera_pos.x = MIN( camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT]));
camera_pos.x = MAX( camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_LEFT]));
} else {
if (h_ofs<0) {
camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs;
} else {
camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs;
}
}
if (v_drag_enabled) {
camera_pos.y = MIN( camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM]));
camera_pos.y = MAX( camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_TOP]));
} else {
if (v_ofs<0) {
camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs;
} else {
camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs;
}
}
}
if (smoothing>0.0) {
float c = smoothing*get_fixed_process_delta_time();
smoothed_camera_pos = ((new_camera_pos-smoothed_camera_pos)*c)+smoothed_camera_pos;
ret_camera_pos=smoothed_camera_pos;
// camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing;
} else {
ret_camera_pos=smoothed_camera_pos=camera_pos;
}
} else {
ret_camera_pos=smoothed_camera_pos=camera_pos=new_camera_pos;
first=false;
}
Point2 screen_offset = (centered ? (screen_size * 0.5 * zoom) : Point2());;
screen_offset+=offset;
Rect2 screen_rect(-screen_offset+ret_camera_pos,screen_size);
if (screen_rect.pos.x + screen_rect.size.x > limit[MARGIN_RIGHT])
screen_rect.pos.x = limit[MARGIN_RIGHT] - screen_rect.size.x;
if (screen_rect.pos.y + screen_rect.size.y > limit[MARGIN_BOTTOM])
screen_rect.pos.y = limit[MARGIN_BOTTOM] - screen_rect.size.y;
if (screen_rect.pos.x < limit[MARGIN_LEFT])
screen_rect.pos.x=limit[MARGIN_LEFT];
if (screen_rect.pos.y < limit[MARGIN_TOP])
screen_rect.pos.y =limit[MARGIN_TOP];
camera_screen_center=screen_rect.pos+screen_rect.size*0.5;
Matrix32 xform;
xform.scale_basis(zoom);
xform.set_origin(screen_rect.pos/*.floor()*/);
/*
if (0) {
xform = get_global_transform() * xform;
} else {
xform.elements[2]+=get_global_transform().get_origin();
}
*/
return (xform).affine_inverse();
}
void Camera2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_FIXED_PROCESS: {
_update_scroll();
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
if (!is_fixed_processing())
_update_scroll();
} break;
case NOTIFICATION_ENTER_SCENE: {
viewport = NULL;
Node *n=this;
while(n){
viewport = n->cast_to<Viewport>();
if (viewport)
break;
n=n->get_parent();
}
canvas = get_canvas();
RID vp = viewport->get_viewport();
group_name = "__cameras_"+itos(vp.get_id());
canvas_group_name ="__cameras_c"+itos(canvas.get_id());
add_to_group(group_name);
add_to_group(canvas_group_name);
_update_scroll();
first=true;
} break;
case NOTIFICATION_EXIT_SCENE: {
if (is_current()) {
if (viewport) {
viewport->set_canvas_transform( Matrix32() );
}
}
remove_from_group(group_name);
remove_from_group(canvas_group_name);
viewport=NULL;
} break;
}
}
void Camera2D::set_offset(const Vector2& p_offset) {
offset=p_offset;
_update_scroll();
}
Vector2 Camera2D::get_offset() const{
return offset;
}
void Camera2D::set_centered(bool p_centered){
centered=p_centered;
_update_scroll();
}
bool Camera2D::is_centered() const {
return centered;
}
void Camera2D::_make_current(Object *p_which) {
if (p_which==this) {
current=true;
_update_scroll();
} else {
current=false;
}
}
void Camera2D::_set_current(bool p_current) {
if (p_current)
make_current();
current=p_current;
}
bool Camera2D::is_current() const {
return current;
}
void Camera2D::make_current() {
if (!is_inside_scene()) {
current=true;
} else {
get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,group_name,"_make_current",this);
}
}
void Camera2D::set_limit(Margin p_margin,int p_limit) {
ERR_FAIL_INDEX(p_margin,4);
limit[p_margin]=p_limit;
}
int Camera2D::get_limit(Margin p_margin) const{
ERR_FAIL_INDEX_V(p_margin,4,0);
return limit[p_margin];
}
void Camera2D::set_drag_margin(Margin p_margin,float p_drag_margin) {
ERR_FAIL_INDEX(p_margin,4);
drag_margin[p_margin]=p_drag_margin;
}
float Camera2D::get_drag_margin(Margin p_margin) const{
ERR_FAIL_INDEX_V(p_margin,4,0);
return drag_margin[p_margin];
}
Vector2 Camera2D::get_camera_pos() const {
return camera_pos;
}
void Camera2D::force_update_scroll() {
_update_scroll();
}
void Camera2D::set_follow_smoothing(float p_speed) {
smoothing=p_speed;
if (smoothing>0)
set_fixed_process(true);
else
set_fixed_process(false);
}
float Camera2D::get_follow_smoothing() const{
return smoothing;
}
Point2 Camera2D::get_camera_screen_center() const {
return camera_screen_center;
}
void Camera2D::set_h_drag_enabled(bool p_enabled) {
h_drag_enabled=p_enabled;
}
bool Camera2D::is_h_drag_enabled() const{
return h_drag_enabled;
}
void Camera2D::set_v_drag_enabled(bool p_enabled){
v_drag_enabled=p_enabled;
}
bool Camera2D::is_v_drag_enabled() const{
return v_drag_enabled;
}
void Camera2D::set_v_offset(float p_offset) {
v_ofs=p_offset;
}
float Camera2D::get_v_offset() const{
return v_ofs;
}
void Camera2D::set_h_offset(float p_offset){
h_ofs=p_offset;
}
float Camera2D::get_h_offset() const{
return h_ofs;
}
void Camera2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_offset","offset"),&Camera2D::set_offset);
ObjectTypeDB::bind_method(_MD("get_offset"),&Camera2D::get_offset);
ObjectTypeDB::bind_method(_MD("set_centered","centered"),&Camera2D::set_centered);
ObjectTypeDB::bind_method(_MD("is_centered"),&Camera2D::is_centered);
ObjectTypeDB::bind_method(_MD("make_current"),&Camera2D::make_current);
ObjectTypeDB::bind_method(_MD("_make_current"),&Camera2D::_make_current);
ObjectTypeDB::bind_method(_MD("_update_scroll"),&Camera2D::_update_scroll);
ObjectTypeDB::bind_method(_MD("_set_current","current"),&Camera2D::_set_current);
ObjectTypeDB::bind_method(_MD("is_current"),&Camera2D::is_current);
ObjectTypeDB::bind_method(_MD("set_limit","margin","limit"),&Camera2D::set_limit);
ObjectTypeDB::bind_method(_MD("get_limit","margin"),&Camera2D::get_limit);
ObjectTypeDB::bind_method(_MD("set_v_drag_enabled","enabled"),&Camera2D::set_v_drag_enabled);
ObjectTypeDB::bind_method(_MD("is_v_drag_enabled"),&Camera2D::is_v_drag_enabled);
ObjectTypeDB::bind_method(_MD("set_h_drag_enabled","enabled"),&Camera2D::set_h_drag_enabled);
ObjectTypeDB::bind_method(_MD("is_h_drag_enabled"),&Camera2D::is_h_drag_enabled);
ObjectTypeDB::bind_method(_MD("set_v_offset","ofs"),&Camera2D::set_v_offset);
ObjectTypeDB::bind_method(_MD("get_v_offset"),&Camera2D::get_v_offset);
ObjectTypeDB::bind_method(_MD("set_h_offset","ofs"),&Camera2D::set_h_offset);
ObjectTypeDB::bind_method(_MD("get_h_offset"),&Camera2D::get_h_offset);
ObjectTypeDB::bind_method(_MD("set_drag_margin","margin","drag_margin"),&Camera2D::set_drag_margin);
ObjectTypeDB::bind_method(_MD("get_drag_margin","margin"),&Camera2D::get_drag_margin);
ObjectTypeDB::bind_method(_MD("get_camera_pos"),&Camera2D::get_camera_pos);
ObjectTypeDB::bind_method(_MD("get_camera_screen_center"),&Camera2D::get_camera_screen_center);
ObjectTypeDB::bind_method(_MD("set_zoom"),&Camera2D::set_zoom);
ObjectTypeDB::bind_method(_MD("get_zoom"),&Camera2D::get_zoom);
ObjectTypeDB::bind_method(_MD("set_follow_smoothing","follow_smoothing"),&Camera2D::set_follow_smoothing);
ObjectTypeDB::bind_method(_MD("get_follow_smoothing"),&Camera2D::get_follow_smoothing);
ObjectTypeDB::bind_method(_MD("force_update_scroll"),&Camera2D::force_update_scroll);
ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_offset"),_SCS("get_offset"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"centered"),_SCS("set_centered"),_SCS("is_centered"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"current"),_SCS("_set_current"),_SCS("is_current"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"smoothing"),_SCS("set_follow_smoothing"),_SCS("get_follow_smoothing") );
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"zoom"),_SCS("set_zoom"),_SCS("get_zoom") );
ADD_PROPERTYI( PropertyInfo(Variant::INT,"limit/left"),_SCS("set_limit"),_SCS("get_limit"),MARGIN_LEFT);
ADD_PROPERTYI( PropertyInfo(Variant::INT,"limit/top"),_SCS("set_limit"),_SCS("get_limit"),MARGIN_TOP);
ADD_PROPERTYI( PropertyInfo(Variant::INT,"limit/right"),_SCS("set_limit"),_SCS("get_limit"),MARGIN_RIGHT);
ADD_PROPERTYI( PropertyInfo(Variant::INT,"limit/bottom"),_SCS("set_limit"),_SCS("get_limit"),MARGIN_BOTTOM);
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"drag_margin/h_enabled"),_SCS("set_h_drag_enabled"),_SCS("is_h_drag_enabled") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"drag_margin/v_enabled"),_SCS("set_v_drag_enabled"),_SCS("is_v_drag_enabled") );
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/left",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_LEFT);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/top",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_TOP);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/right",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_RIGHT);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/bottom",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_BOTTOM);
}
Camera2D::Camera2D() {
centered=true;
current=false;
limit[MARGIN_LEFT]=-10000000;
limit[MARGIN_TOP]=-10000000;
limit[MARGIN_RIGHT]=10000000;
limit[MARGIN_BOTTOM]=10000000;
drag_margin[MARGIN_LEFT]=0.2;
drag_margin[MARGIN_TOP]=0.2;
drag_margin[MARGIN_RIGHT]=0.2;
drag_margin[MARGIN_BOTTOM]=0.2;
camera_pos=Vector2();
smoothing=0.0;
zoom = Vector2(1, 1);
h_drag_enabled=true;
v_drag_enabled=true;
h_ofs=0;
v_ofs=0;
}

118
scene/2d/camera_2d.h Normal file
View File

@ -0,0 +1,118 @@
/*************************************************************************/
/* camera_2d.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_2D_H
#define CAMERA_2D_H
#include "scene/2d/node_2d.h"
#include "scene/main/viewport.h"
class Camera2D : public Node2D {
OBJ_TYPE( Camera2D, Node2D );
protected:
Point2 camera_pos;
Point2 smoothed_camera_pos;
bool first;
Viewport *viewport;
StringName group_name;
StringName canvas_group_name;
RID canvas;
Vector2 offset;
Vector2 zoom;
bool centered;
bool current;
float smoothing;
int limit[4];
float drag_margin[4];
bool h_drag_enabled;
bool v_drag_enabled;
float h_ofs;
float v_ofs;
Point2 camera_screen_center;
void _update_scroll();
void _make_current(Object *p_which);
void _set_current(bool p_current);
protected:
virtual Matrix32 get_camera_transform();
void _notification(int p_what);
static void _bind_methods();
public:
void set_offset(const Vector2& p_offset);
Vector2 get_offset() const;
void set_centered(bool p_centered);
bool is_centered() const;
void set_limit(Margin p_margin,int p_limit);
int get_limit(Margin p_margin) const;
void set_h_drag_enabled(bool p_enabled);
bool is_h_drag_enabled() const;
void set_v_drag_enabled(bool p_enabled);
bool is_v_drag_enabled() const;
void set_drag_margin(Margin p_margin,float p_drag_margin);
float get_drag_margin(Margin p_margin) const;
void set_v_offset(float p_offset);
float get_v_offset() const;
void set_h_offset(float p_offset);
float get_h_offset() const;
void set_follow_smoothing(float p_speed);
float get_follow_smoothing() const;
void make_current();
bool is_current() const;
void set_zoom(const Vector2& p_zoom);
Vector2 get_zoom() const;
Point2 get_camera_screen_center() const;
Vector2 get_camera_pos() const;
void force_update_scroll();
Camera2D();
};
#endif // CAMERA_2D_H

875
scene/2d/canvas_item.cpp Normal file
View File

@ -0,0 +1,875 @@
/*************************************************************************/
/* canvas_item.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 "canvas_item.h"
#include "servers/visual_server.h"
#include "scene/main/viewport.h"
#include "scene/main/canvas_layer.h"
#include "message_queue.h"
#include "scene/scene_string_names.h"
#include "scene/resources/font.h"
#include "scene/resources/texture.h"
#include "scene/resources/style_box.h"
bool CanvasItem::is_visible() const {
if (!is_inside_scene())
return false;
const CanvasItem *p=this;
while(p) {
if (p->hidden)
return false;
p=p->get_parent_item();
}
return true;
}
bool CanvasItem::is_hidden() const {
/*if (!is_inside_scene())
return false;*/
return hidden;
}
void CanvasItem::_propagate_visibility_changed(bool p_visible) {
notification(NOTIFICATION_VISIBILITY_CHANGED);
if (p_visible)
update(); //todo optimize
else
emit_signal(SceneStringNames::get_singleton()->hide);
_block();
for(int i=0;i<get_child_count();i++) {
CanvasItem *c=get_child(i)->cast_to<CanvasItem>();
if (c && c->hidden!=p_visible) //should the toplevels stop propagation? i think so but..
c->_propagate_visibility_changed(p_visible);
}
_unblock();
}
void CanvasItem::show() {
if (!hidden)
return;
hidden=false;
VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,true);
if (!is_inside_scene())
return;
if (is_visible()) {
_propagate_visibility_changed(true);
}
}
void CanvasItem::hide() {
if (hidden)
return;
bool propagate=is_inside_scene() && is_visible();
hidden=true;
VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,false);
if (!is_inside_scene())
return;
if (propagate)
_propagate_visibility_changed(false);
}
Variant CanvasItem::edit_get_state() const {
return Variant();
}
void CanvasItem::edit_set_state(const Variant& p_state) {
}
void CanvasItem::edit_set_rect(const Rect2& p_edit_rect) {
//used by editors, implement at will
}
void CanvasItem::edit_rotate(float p_rot) {
}
Size2 CanvasItem::edit_get_minimum_size() const {
return Size2(-1,-1); //no limit
}
void CanvasItem::_update_callback() {
if (!is_inside_scene()) {
pending_update=false;
return;
}
VisualServer::get_singleton()->canvas_item_clear(get_canvas_item());
//todo updating = true - only allow drawing here
if (is_visible()) { //todo optimize this!!
if (first_draw) {
notification(NOTIFICATION_VISIBILITY_CHANGED);
first_draw=false;
}
drawing=true;
notification(NOTIFICATION_DRAW);
emit_signal(SceneStringNames::get_singleton()->draw);
if (get_script_instance()) {
Variant::CallError err;
get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw,NULL,0);
}
drawing=false;
}
//todo updating = false
pending_update=false; // don't change to false until finished drawing (avoid recursive update)
}
Matrix32 CanvasItem::get_global_transform_with_canvas() const {
const CanvasItem *ci = this;
Matrix32 xform;
const CanvasItem *last_valid=NULL;
while(ci) {
last_valid=ci;
xform = ci->get_transform() * xform;
ci=ci->get_parent_item();
}
if (last_valid->canvas_layer)
return last_valid->canvas_layer->get_transform() * xform;
else
return xform;
}
Matrix32 CanvasItem::get_global_transform() const {
if (global_invalid) {
const CanvasItem *pi = get_parent_item();
if (pi)
global_transform = pi->get_global_transform() * get_transform();
else
global_transform = get_transform();
global_invalid=false;
}
return global_transform;
}
void CanvasItem::_queue_sort_children() {
if (pending_children_sort)
return;
pending_children_sort=true;
MessageQueue::get_singleton()->push_call(this,"_sort_children");
}
void CanvasItem::_sort_children() {
pending_children_sort=false;
if (!is_inside_scene())
return;
for(int i=0;i<get_child_count();i++) {
Node *n = get_child(i);
CanvasItem *ci=n->cast_to<CanvasItem>();
if (ci) {
if (ci->toplevel || ci->group!="")
continue;
VisualServer::get_singleton()->canvas_item_raise(n->cast_to<CanvasItem>()->canvas_item);
}
}
}
void CanvasItem::_raise_self() {
if (!is_inside_scene())
return;
VisualServer::get_singleton()->canvas_item_raise(canvas_item);
}
void CanvasItem::_enter_canvas() {
if ((!get_parent() || !get_parent()->cast_to<CanvasItem>()) || toplevel) {
Node *n = this;
viewport=NULL;
canvas_layer=NULL;
while(n) {
if (n->cast_to<Viewport>()) {
viewport = n->cast_to<Viewport>();
break;
}
if (!canvas_layer && n->cast_to<CanvasLayer>()) {
canvas_layer = n->cast_to<CanvasLayer>();
}
n=n->get_parent();
}
RID canvas;
if (canvas_layer)
canvas=canvas_layer->get_world_2d()->get_canvas();
else
canvas=viewport->find_world_2d()->get_canvas();
VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,canvas);
group = "root_canvas"+itos(canvas.get_id());
add_to_group(group);
get_scene()->call_group(SceneMainLoop::GROUP_CALL_UNIQUE,group,"_raise_self");
} else {
CanvasItem *parent = get_parent_item();
viewport=parent->viewport;
VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,parent->get_canvas_item());
parent->_queue_sort_children();
}
if (!viewport) {
print_line("no viewport wtf!");
}
pending_update=false;
update();
notification(NOTIFICATION_ENTER_CANVAS);
}
void CanvasItem::_exit_canvas() {
notification(NOTIFICATION_EXIT_CANVAS,true); //reverse the notification
VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,RID());
viewport=NULL;
canvas_layer=NULL;
group="";
}
void CanvasItem::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_SCENE: {
first_draw=true;
pending_children_sort=false;
if (get_parent()) {
CanvasItem *ci = get_parent()->cast_to<CanvasItem>();
if (ci)
C=ci->children_items.push_back(this);
}
_enter_canvas();
if (!block_transform_notify && !xform_change.in_list()) {
get_scene()->xform_change_list.add(&xform_change);
}
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
if (group!="") {
get_scene()->call_group(SceneMainLoop::GROUP_CALL_UNIQUE,group,"_raise_self");
} else {
CanvasItem *p = get_parent_item();
ERR_FAIL_COND(!p);
p->_queue_sort_children();
}
} break;
case NOTIFICATION_EXIT_SCENE: {
if (xform_change.in_list())
get_scene()->xform_change_list.remove(&xform_change);
_exit_canvas();
if (C)
get_parent()->cast_to<CanvasItem>()->children_items.erase(C);
} break;
case NOTIFICATION_DRAW: {
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
emit_signal(SceneStringNames::get_singleton()->visibility_changed);
} break;
}
}
void CanvasItem::_set_visible_(bool p_visible) {
if (p_visible)
show();
else
hide();
}
bool CanvasItem::_is_visible_() const {
return !is_hidden();
}
void CanvasItem::update() {
if (!is_inside_scene())
return;
if (pending_update)
return;
pending_update=true;
MessageQueue::get_singleton()->push_call(this,"_update_callback");
}
void CanvasItem::set_opacity(float p_opacity) {
opacity=p_opacity;
VisualServer::get_singleton()->canvas_item_set_opacity(canvas_item,opacity);
}
float CanvasItem::get_opacity() const {
return opacity;
}
void CanvasItem::set_as_toplevel(bool p_toplevel) {
if (toplevel==p_toplevel)
return;
if (!is_inside_scene()) {
toplevel=p_toplevel;
return;
}
_exit_canvas();
toplevel=p_toplevel;
_enter_canvas();
}
bool CanvasItem::is_set_as_toplevel() const {
return toplevel;
}
CanvasItem *CanvasItem::get_parent_item() const {
if (toplevel)
return NULL;
Node *parent = get_parent();
if (!parent)
return NULL;
return parent->cast_to<CanvasItem>();
}
void CanvasItem::set_self_opacity(float p_self_opacity) {
self_opacity=p_self_opacity;
VisualServer::get_singleton()->canvas_item_set_self_opacity(canvas_item,self_opacity);
}
float CanvasItem::get_self_opacity() const {
return self_opacity;
}
void CanvasItem::set_blend_mode(BlendMode p_blend_mode) {
ERR_FAIL_INDEX(p_blend_mode,4);
blend_mode=p_blend_mode;
VisualServer::get_singleton()->canvas_item_set_blend_mode(canvas_item,VS::MaterialBlendMode(blend_mode));
}
CanvasItem::BlendMode CanvasItem::get_blend_mode() const {
return blend_mode;
}
void CanvasItem::item_rect_changed() {
update();
emit_signal(SceneStringNames::get_singleton()->item_rect_changed);
}
void CanvasItem::draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
VisualServer::get_singleton()->canvas_item_add_line(canvas_item,p_from,p_to,p_color,p_width);
}
void CanvasItem::draw_rect(const Rect2& p_rect, const Color& p_color) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
VisualServer::get_singleton()->canvas_item_add_rect(canvas_item,p_rect,p_color);
}
void CanvasItem::draw_circle(const Point2& p_pos, float p_radius, const Color& p_color) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
VisualServer::get_singleton()->canvas_item_add_circle(canvas_item,p_pos,p_radius,p_color);
}
void CanvasItem::draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
ERR_FAIL_COND(p_texture.is_null());
p_texture->draw(canvas_item,p_pos);
}
void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_rect, bool p_tile,const Color& p_modulate) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
ERR_FAIL_COND(p_texture.is_null());
p_texture->draw_rect(canvas_item,p_rect,p_tile,p_modulate);
}
void CanvasItem::draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
ERR_FAIL_COND(p_texture.is_null());
p_texture->draw_rect_region(canvas_item,p_rect,p_src_rect,p_modulate);
}
void CanvasItem::draw_style_box(const Ref<StyleBox>& p_style_box,const Rect2& p_rect) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
ERR_FAIL_COND(p_style_box.is_null());
p_style_box->draw(canvas_item,p_rect);
}
void CanvasItem::draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, Ref<Texture> p_texture,float p_width) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
VisualServer::get_singleton()->canvas_item_add_primitive(canvas_item,p_points,p_colors,p_uvs,rid,p_width);
}
void CanvasItem::draw_set_transform(const Point2& p_offset, float p_rot, const Size2& p_scale) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
Matrix32 xform(p_rot,p_offset);
xform.scale_basis(p_scale);
VisualServer::get_singleton()->canvas_item_set_transform(canvas_item,xform);
}
void CanvasItem::draw_polygon(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, Ref<Texture> p_texture) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item,p_points,p_colors,p_uvs,rid);
}
void CanvasItem::draw_colored_polygon(const Vector<Point2>& p_points, const Color& p_color,const Vector<Point2>& p_uvs, Ref<Texture> p_texture) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
Vector<Color> colors;
colors.push_back(p_color);
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item,p_points,colors,p_uvs,rid);
}
void CanvasItem::draw_string(const Ref<Font>& p_font,const Point2& p_pos, const String& p_text,const Color& p_modulate,int p_clip_w) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
ERR_FAIL_COND(p_font.is_null());
p_font->draw(canvas_item,p_pos,p_text,p_modulate,p_clip_w);
}
float CanvasItem::draw_char(const Ref<Font>& p_font,const Point2& p_pos, const String& p_char,const String& p_next,const Color& p_modulate) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_V(0);
}
ERR_FAIL_COND_V(p_char.length()!=1,0);
ERR_FAIL_COND_V(p_font.is_null(),0);
return p_font->draw_char(canvas_item,p_pos,p_char[0],p_next.c_str()[0],p_modulate);
}
void CanvasItem::_notify_transform(CanvasItem *p_node) {
if (p_node->xform_change.in_list() && p_node->global_invalid)
return; //nothing to do
p_node->global_invalid=true;
if (!p_node->xform_change.in_list()) {
if (!p_node->block_transform_notify) {
if (p_node->is_inside_scene())
get_scene()->xform_change_list.add(&p_node->xform_change);
}
}
for(List<CanvasItem*>::Element *E=p_node->children_items.front();E;E=E->next()) {
CanvasItem* ci=E->get();
if (ci->toplevel)
continue;
_notify_transform(ci);
}
}
Rect2 CanvasItem::get_viewport_rect() const {
ERR_FAIL_COND_V(!is_inside_scene(),Rect2());
return viewport->get_visible_rect();
}
RID CanvasItem::get_canvas() const {
ERR_FAIL_COND_V(!is_inside_scene(),RID());
if (canvas_layer)
return canvas_layer->get_world_2d()->get_canvas();
else
return viewport->find_world_2d()->get_canvas();
}
CanvasItem *CanvasItem::get_toplevel() const {
CanvasItem *ci=const_cast<CanvasItem*>(this);
while(!ci->toplevel && ci->get_parent() && ci->get_parent()->cast_to<CanvasItem>()) {
ci=ci->get_parent()->cast_to<CanvasItem>();
}
return ci;
}
Viewport *CanvasItem::get_viewport() const {
return viewport;
}
Ref<World2D> CanvasItem::get_world_2d() const {
ERR_FAIL_COND_V(!is_inside_scene(),Ref<World2D>());
CanvasItem *tl=get_toplevel();
if (tl->canvas_layer) {
return tl->canvas_layer->get_world_2d();
} else if (tl->viewport) {
return tl->viewport->find_world_2d();
} else {
return Ref<World2D>();
}
}
RID CanvasItem::get_viewport_rid() const {
ERR_FAIL_COND_V(!is_inside_scene(),RID());
return viewport->get_viewport();
}
void CanvasItem::set_block_transform_notify(bool p_enable) {
block_transform_notify=p_enable;
}
bool CanvasItem::is_block_transform_notify_enabled() const {
return block_transform_notify;
}
void CanvasItem::set_on_top(bool p_on_top) {
if (on_top==p_on_top)
return;
on_top=p_on_top;
VisualServer::get_singleton()->canvas_item_set_on_top(canvas_item,on_top);
}
bool CanvasItem::is_on_top() const {
return on_top;
}
void CanvasItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_sort_children"),&CanvasItem::_sort_children);
ObjectTypeDB::bind_method(_MD("_raise_self"),&CanvasItem::_raise_self);
ObjectTypeDB::bind_method(_MD("_update_callback"),&CanvasItem::_update_callback);
ObjectTypeDB::bind_method(_MD("_set_visible_"),&CanvasItem::_set_visible_);
ObjectTypeDB::bind_method(_MD("_is_visible_"),&CanvasItem::_is_visible_);
ObjectTypeDB::bind_method(_MD("edit_set_state","state"),&CanvasItem::edit_set_state);
ObjectTypeDB::bind_method(_MD("edit_get"),&CanvasItem::edit_get_state);
ObjectTypeDB::bind_method(_MD("edit_set_rect","rect"),&CanvasItem::edit_set_rect);
ObjectTypeDB::bind_method(_MD("edit_rotate","degrees"),&CanvasItem::edit_rotate);
ObjectTypeDB::bind_method(_MD("get_item_rect"),&CanvasItem::get_item_rect);
//ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform);
ObjectTypeDB::bind_method(_MD("get_canvas_item"),&CanvasItem::get_canvas_item);
ObjectTypeDB::bind_method(_MD("is_visible"),&CanvasItem::is_visible);
ObjectTypeDB::bind_method(_MD("is_hidden"),&CanvasItem::is_hidden);
ObjectTypeDB::bind_method(_MD("show"),&CanvasItem::show);
ObjectTypeDB::bind_method(_MD("hide"),&CanvasItem::hide);
ObjectTypeDB::bind_method(_MD("update"),&CanvasItem::update);
ObjectTypeDB::bind_method(_MD("set_as_toplevel","enable"),&CanvasItem::set_as_toplevel);
ObjectTypeDB::bind_method(_MD("is_set_as_toplevel"),&CanvasItem::is_set_as_toplevel);
ObjectTypeDB::bind_method(_MD("set_blend_mode","blend_mode"),&CanvasItem::set_blend_mode);
ObjectTypeDB::bind_method(_MD("get_blend_mode"),&CanvasItem::get_blend_mode);
ObjectTypeDB::bind_method(_MD("set_opacity","opacity"),&CanvasItem::set_opacity);
ObjectTypeDB::bind_method(_MD("get_opacity"),&CanvasItem::get_opacity);
ObjectTypeDB::bind_method(_MD("set_self_opacity","self_opacity"),&CanvasItem::set_self_opacity);
ObjectTypeDB::bind_method(_MD("get_self_opacity"),&CanvasItem::get_self_opacity);
ObjectTypeDB::bind_method(_MD("set_on_top","on_top"),&CanvasItem::set_on_top);
ObjectTypeDB::bind_method(_MD("is_on_top"),&CanvasItem::is_on_top);
//ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform);
ObjectTypeDB::bind_method(_MD("draw_line","from","to","color","width"),&CanvasItem::draw_line,DEFVAL(1.0));
ObjectTypeDB::bind_method(_MD("draw_rect","rect","color"),&CanvasItem::draw_rect);
ObjectTypeDB::bind_method(_MD("draw_circle","pos","radius","color"),&CanvasItem::draw_circle);
ObjectTypeDB::bind_method(_MD("draw_texture","texture:Texture","pos"),&CanvasItem::draw_texture);
ObjectTypeDB::bind_method(_MD("draw_texture_rect","texture:Texture","rect","tile","modulate"),&CanvasItem::draw_texture_rect,DEFVAL(false),DEFVAL(Color(1,1,1)));
ObjectTypeDB::bind_method(_MD("draw_texture_rect_region","texture:Texture","rect","src_rect","modulate"),&CanvasItem::draw_texture_rect_region,DEFVAL(Color(1,1,1)));
ObjectTypeDB::bind_method(_MD("draw_style_box","style_box:StyleBox","rect"),&CanvasItem::draw_style_box);
ObjectTypeDB::bind_method(_MD("draw_primitive","points","colors","uvs","texture:Texture","width"),&CanvasItem::draw_primitive,DEFVAL(Array()),DEFVAL(Ref<Texture>()),DEFVAL(1.0));
ObjectTypeDB::bind_method(_MD("draw_polygon","points","colors","uvs","texture:Texture"),&CanvasItem::draw_primitive,DEFVAL(Array()),DEFVAL(Ref<Texture>()));
ObjectTypeDB::bind_method(_MD("draw_colored_polygon","points","color","uvs","texture:Texture"),&CanvasItem::draw_primitive,DEFVAL(Array()),DEFVAL(Ref<Texture>()));
ObjectTypeDB::bind_method(_MD("draw_string","font:Font","pos","text","modulate","clip_w"),&CanvasItem::draw_string,DEFVAL(Color(1,1,1)),DEFVAL(-1));
ObjectTypeDB::bind_method(_MD("draw_char","font:Font","pos","char","next","modulate"),&CanvasItem::draw_char,DEFVAL(Color(1,1,1)));
ObjectTypeDB::bind_method(_MD("draw_set_transform","pos","rot","scale"),&CanvasItem::draw_set_transform);
ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform);
ObjectTypeDB::bind_method(_MD("get_global_transform"),&CanvasItem::get_global_transform);
ObjectTypeDB::bind_method(_MD("get_viewport_transform"),&CanvasItem::get_viewport_transform);
ObjectTypeDB::bind_method(_MD("get_viewport_rect"),&CanvasItem::get_viewport_rect);
ObjectTypeDB::bind_method(_MD("get_canvas"),&CanvasItem::get_canvas);
ObjectTypeDB::bind_method(_MD("get_world_2d"),&CanvasItem::get_world_2d);
ObjectTypeDB::bind_method(_MD("get_viewport"),&CanvasItem::get_viewport);
BIND_VMETHOD(MethodInfo("_draw"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"),_SCS("_is_visible_") );
ADD_PROPERTY( PropertyInfo(Variant::REAL,"visibility/opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_opacity"),_SCS("get_opacity") );
ADD_PROPERTY( PropertyInfo(Variant::REAL,"visibility/self_opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_self_opacity"),_SCS("get_self_opacity") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/on_top"), _SCS("set_on_top"),_SCS("is_on_top") );
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul"), _SCS("set_blend_mode"),_SCS("get_blend_mode") );
//exporting these two things doesn't really make much sense i think
//ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), _SCS("set_as_toplevel"),_SCS("is_set_as_toplevel") );
//ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),_SCS("set_transform_notify"),_SCS("is_transform_notify_enabled"));
ADD_SIGNAL( MethodInfo("draw") );
ADD_SIGNAL( MethodInfo("visibility_changed") );
ADD_SIGNAL( MethodInfo("hide") );
ADD_SIGNAL( MethodInfo("item_rect_changed") );
BIND_CONSTANT( BLEND_MODE_MIX );
BIND_CONSTANT( BLEND_MODE_ADD );
BIND_CONSTANT( BLEND_MODE_SUB );
BIND_CONSTANT( BLEND_MODE_MUL );
BIND_CONSTANT( NOTIFICATION_DRAW);
BIND_CONSTANT( NOTIFICATION_VISIBILITY_CHANGED );
BIND_CONSTANT( NOTIFICATION_ENTER_CANVAS );
BIND_CONSTANT( NOTIFICATION_EXIT_CANVAS );
BIND_CONSTANT( NOTIFICATION_TRANSFORM_CHANGED );
}
Matrix32 CanvasItem::get_viewport_transform() const {
ERR_FAIL_COND_V(!is_inside_scene(),Matrix32());
if (canvas_layer) {
if (viewport) {
return viewport->get_final_transform() * canvas_layer->get_transform();
} else {
return canvas_layer->get_transform();
}
} else if (viewport) {
return viewport->get_final_transform() * viewport->get_canvas_transform();
}
return Matrix32();
}
CanvasItem::CanvasItem() : xform_change(this) {
canvas_item=VisualServer::get_singleton()->canvas_item_create();
hidden=false;
pending_update=false;
opacity=1;
self_opacity=1;
toplevel=false;
pending_children_sort=false;
first_draw=false;
blend_mode=BLEND_MODE_MIX;
drawing=false;
on_top=true;
block_transform_notify=false;
viewport=NULL;
canvas_layer=NULL;
global_invalid=true;
C=NULL;
}
CanvasItem::~CanvasItem() {
VisualServer::get_singleton()->free(canvas_item);
}

209
scene/2d/canvas_item.h Normal file
View File

@ -0,0 +1,209 @@
/*************************************************************************/
/* canvas_item.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 CANVAS_ITEM_H
#define CANVAS_ITEM_H
#include "scene/main/node.h"
#include "scene/resources/texture.h"
#include "scene/main/scene_main_loop.h"
class CanvasLayer;
class Viewport;
class Font;
class StyleBox;
class CanvasItem : public Node {
OBJ_TYPE( CanvasItem, Node );
public:
enum BlendMode {
BLEND_MODE_MIX, //default
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL
};
private:
mutable SelfList<Node> xform_change;
RID canvas_item;
String group;
Viewport *viewport;
CanvasLayer *canvas_layer;
float opacity;
float self_opacity;
List<CanvasItem*> children_items;
List<CanvasItem*>::Element *C;
BlendMode blend_mode;
bool first_draw;
bool hidden;
bool pending_update;
bool toplevel;
bool pending_children_sort;
bool drawing;
bool block_transform_notify;
bool on_top;
mutable Matrix32 global_transform;
mutable bool global_invalid;
void _raise_self();
void _propagate_visibility_changed(bool p_visible);
void _set_visible_(bool p_visible);
bool _is_visible_() const;
void _update_callback();
void _enter_canvas();
void _exit_canvas();
void _queue_sort_children();
void _sort_children();
void _notify_transform(CanvasItem *p_node);
protected:
_FORCE_INLINE_ void _notify_transform() { if (!is_inside_scene()) return; _notify_transform(this); if (!block_transform_notify) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); }
void item_rect_changed();
void _notification(int p_what);
static void _bind_methods();
public:
enum {
NOTIFICATION_TRANSFORM_CHANGED=SceneMainLoop::NOTIFICATION_TRANSFORM_CHANGED, //unique
NOTIFICATION_DRAW=30,
NOTIFICATION_VISIBILITY_CHANGED=31,
NOTIFICATION_ENTER_CANVAS=32,
NOTIFICATION_EXIT_CANVAS=33,
NOTIFICATION_LOCAL_TRANSFORM_CHANGED=35,
NOTIFICATION_WORLD_2D_CHANGED=36,
};
/* EDITOR */
virtual Variant edit_get_state() const;
virtual void edit_set_state(const Variant& p_state);
virtual void edit_set_rect(const Rect2& p_edit_rect);
virtual void edit_rotate(float p_rot);
virtual Size2 edit_get_minimum_size() const;
/* VISIBILITY */
bool is_visible() const;
bool is_hidden() const;
void show();
void hide();
void update();
void set_blend_mode(BlendMode p_blend_mode);
BlendMode get_blend_mode() const;
void set_opacity(float p_opacity);
float get_opacity() const;
void set_self_opacity(float p_self_opacity);
float get_self_opacity() const;
/* DRAWING API */
void draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width=1.0);
void draw_rect(const Rect2& p_rect, const Color& p_color);
void draw_circle(const Point2& p_pos, float p_radius, const Color& p_color);
void draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos);
void draw_texture_rect(const Ref<Texture>& p_texture, const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1));
void draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1));
void draw_style_box(const Ref<StyleBox>& p_style_box,const Rect2& p_rect);
void draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, Ref<Texture> p_texture=Ref<Texture>(),float p_width=1);
void draw_polygon(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), Ref<Texture> p_texture=Ref<Texture>());
void draw_colored_polygon(const Vector<Point2>& p_points, const Color& p_color,const Vector<Point2>& p_uvs=Vector<Point2>(), Ref<Texture> p_texture=Ref<Texture>());
void draw_string(const Ref<Font>& p_font, const Point2& p_pos, const String& p_text,const Color& p_modulate=Color(1,1,1),int p_clip_w=-1);
float draw_char(const Ref<Font>& p_font,const Point2& p_pos, const String& p_char,const String& p_next="",const Color& p_modulate=Color(1,1,1));
void draw_set_transform(const Point2& p_offset, float p_rot, const Size2& p_scale);
/* RECT / TRANSFORM */
void set_as_toplevel(bool p_toplevel);
bool is_set_as_toplevel() const;
void set_on_top(bool p_on_top);
bool is_on_top() const;
CanvasItem *get_parent_item() const;
virtual Rect2 get_item_rect() const=0;
virtual Matrix32 get_transform() const=0;
virtual Matrix32 get_global_transform() const;
virtual Matrix32 get_global_transform_with_canvas() const;
CanvasItem *get_toplevel() const;
_FORCE_INLINE_ RID get_canvas_item() const { return canvas_item; }
void set_block_transform_notify(bool p_enable);
bool is_block_transform_notify_enabled() const;
Matrix32 get_viewport_transform() const;
Rect2 get_viewport_rect() const;
RID get_viewport_rid() const;
RID get_canvas() const;
Ref<World2D> get_world_2d() const;
Viewport *get_viewport() const;
CanvasItem();
~CanvasItem();
};
VARIANT_ENUM_CAST( CanvasItem::BlendMode );
#endif // CANVAS_ITEM_H

View File

@ -0,0 +1,282 @@
/*************************************************************************/
/* collision_object_2d.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_2d.h"
#include "servers/physics_2d_server.h"
void CollisionObject2D::_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 CollisionObject2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_SCENE: {
RID space = get_world_2d()->get_space();
if (area) {
Physics2DServer::get_singleton()->area_set_space(rid,space);
} else
Physics2DServer::get_singleton()->body_set_space(rid,space);
//get space
}
case NOTIFICATION_TRANSFORM_CHANGED: {
if (area)
Physics2DServer::get_singleton()->area_set_transform(rid,get_global_transform());
else
Physics2DServer::get_singleton()->body_set_state(rid,Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform());
} break;
case NOTIFICATION_EXIT_SCENE: {
if (area) {
Physics2DServer::get_singleton()->area_set_space(rid,RID());
} else
Physics2DServer::get_singleton()->body_set_space(rid,RID());
} break;
}
}
void CollisionObject2D::_update_shapes() {
if (!rid.is_valid())
return;
if (area)
Physics2DServer::get_singleton()->area_clear_shapes(rid);
else
Physics2DServer::get_singleton()->body_clear_shapes(rid);
for(int i=0;i<shapes.size();i++) {
if (shapes[i].shape.is_null())
continue;
if (area)
Physics2DServer::get_singleton()->area_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform);
else {
Physics2DServer::get_singleton()->body_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform);
if (shapes[i].trigger)
Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid,i,shapes[i].trigger);
}
}
}
bool CollisionObject2D::_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 CollisionObject2D::_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 CollisionObject2D::_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,"Shape2D",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 CollisionObject2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_shape","shape:Shape2D","transform"),&CollisionObject2D::add_shape,DEFVAL(Matrix32()));
ObjectTypeDB::bind_method(_MD("get_shape_count"),&CollisionObject2D::get_shape_count);
ObjectTypeDB::bind_method(_MD("set_shape","shape_idx","shape:Shape"),&CollisionObject2D::set_shape);
ObjectTypeDB::bind_method(_MD("set_shape_transform","shape_idx","transform"),&CollisionObject2D::set_shape_transform);
ObjectTypeDB::bind_method(_MD("set_shape_as_trigger","shape_idx","enable"),&CollisionObject2D::set_shape_as_trigger);
ObjectTypeDB::bind_method(_MD("get_shape:Shape2D","shape_idx"),&CollisionObject2D::get_shape);
ObjectTypeDB::bind_method(_MD("get_shape_transform","shape_idx"),&CollisionObject2D::get_shape_transform);
ObjectTypeDB::bind_method(_MD("is_shape_set_as_trigger","shape_idx"),&CollisionObject2D::is_shape_set_as_trigger);
ObjectTypeDB::bind_method(_MD("remove_shape","shape_idx"),&CollisionObject2D::remove_shape);
ObjectTypeDB::bind_method(_MD("clear_shapes"),&CollisionObject2D::clear_shapes);
ObjectTypeDB::bind_method(_MD("get_rid"),&CollisionObject2D::get_rid);
}
void CollisionObject2D::add_shape(const Ref<Shape2D>& p_shape, const Matrix32& p_transform) {
ShapeData sdata;
sdata.shape=p_shape;
sdata.xform=p_transform;
sdata.trigger=false;
shapes.push_back(sdata);
_update_shapes();
}
int CollisionObject2D::get_shape_count() const {
return shapes.size();
}
void CollisionObject2D::set_shape(int p_shape_idx, const Ref<Shape2D>& p_shape) {
ERR_FAIL_INDEX(p_shape_idx,shapes.size());
shapes[p_shape_idx].shape=p_shape;
_update_shapes();
}
void CollisionObject2D::set_shape_transform(int p_shape_idx, const Matrix32& p_transform) {
ERR_FAIL_INDEX(p_shape_idx,shapes.size());
shapes[p_shape_idx].xform=p_transform;
_update_shapes();
}
Ref<Shape2D> CollisionObject2D::get_shape(int p_shape_idx) const {
ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),Ref<Shape2D>());
return shapes[p_shape_idx].shape;
}
Matrix32 CollisionObject2D::get_shape_transform(int p_shape_idx) const {
ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),Matrix32());
return shapes[p_shape_idx].xform;
}
void CollisionObject2D::remove_shape(int p_shape_idx) {
ERR_FAIL_INDEX(p_shape_idx,shapes.size());
shapes.remove(p_shape_idx);
_update_shapes();
}
void CollisionObject2D::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()) {
Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid,p_shape_idx,p_trigger);
}
}
bool CollisionObject2D::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;
}
void CollisionObject2D::clear_shapes() {
shapes.clear();
_update_shapes();
}
CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
rid=p_rid;
area=p_area;
if (p_area) {
Physics2DServer::get_singleton()->area_attach_object_instance_ID(rid,get_instance_ID());
} else {
Physics2DServer::get_singleton()->body_attach_object_instance_ID(rid,get_instance_ID());
}
}
CollisionObject2D::CollisionObject2D() {
//owner=
}
CollisionObject2D::~CollisionObject2D() {
Physics2DServer::get_singleton()->free(rid);
}

View File

@ -0,0 +1,89 @@
/*************************************************************************/
/* collision_object_2d.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_2D_H
#define COLLISION_OBJECT_2D_H
#include "scene/2d/node_2d.h"
#include "scene/resources/shape_2d.h"
class CollisionObject2D : public Node2D {
OBJ_TYPE( CollisionObject2D, Node2D );
bool area;
RID rid;
struct ShapeData {
Matrix32 xform;
Ref<Shape2D> shape;
bool trigger;
ShapeData() {
trigger=false;
}
};
Vector<ShapeData> shapes;
void _update_shapes();
friend class CollisionShape2D;
friend class CollisionPolygon2D;
void _update_shapes_from_children();
protected:
CollisionObject2D(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<Shape2D>& p_shape, const Matrix32& p_transform=Matrix32());
int get_shape_count() const;
void set_shape(int p_shape_idx, const Ref<Shape2D>& p_shape);
void set_shape_transform(int p_shape_idx, const Matrix32& p_transform);
Ref<Shape2D> get_shape(int p_shape_idx) const;
Matrix32 get_shape_transform(int p_shape_idx) const;
void set_shape_as_trigger(int p_shape_idx, bool p_trigger);
bool is_shape_set_as_trigger(int p_shape_idx) const;
void remove_shape(int p_shape_idx);
void clear_shapes();
_FORCE_INLINE_ RID get_rid() const { return rid; }
CollisionObject2D();
~CollisionObject2D();
};
#endif // COLLISION_OBJECT_2D_H

View File

@ -0,0 +1,187 @@
/*************************************************************************/
/* collision_polygon_2d.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_polygon_2d.h"
#include "collision_object_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>();
ERR_FAIL_COND(!co);
if (polygon.size()==0)
return;
bool solids=build_mode==BUILD_SOLIDS;
if (solids) {
//here comes the sun, lalalala
//decompose concave into multiple convex polygons and add them
Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon);
for(int i=0;i<decomp.size();i++) {
Ref<ConvexPolygonShape2D> convex = memnew( ConvexPolygonShape2D );
convex->set_points(decomp[i]);
co->add_shape(convex,get_transform());
}
} else {
Ref<ConcavePolygonShape2D> concave = memnew( ConcavePolygonShape2D );
DVector<Vector2> segments;
segments.resize(polygon.size()*2);
DVector<Vector2>::Write w=segments.write();
for(int i=0;i<polygon.size();i++) {
w[(i<<1)+0]=polygon[i];
w[(i<<1)+1]=polygon[(i+1)%polygon.size()];
}
w=DVector<Vector2>::Write();
concave->set_segments(segments);
co->add_shape(concave,get_transform());
}
//co->add_shape(shape,get_transform());
}
void CollisionPolygon2D::_update_parent() {
Node *parent = get_parent();
if (!parent)
return;
CollisionObject2D *co = parent->cast_to<CollisionObject2D>();
if (!co)
return;
co->_update_shapes_from_children();
}
void CollisionPolygon2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (!is_inside_scene())
break;
_update_parent();
} break;
case NOTIFICATION_DRAW: {
for(int i=0;i<polygon.size();i++) {
Vector2 p = polygon[i];
Vector2 n = polygon[(i+1)%polygon.size()];
draw_line(p,n,Color(0,0.6,0.7,0.5),3);
}
Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon);
#define DEBUG_DECOMPOSE
#ifdef DEBUG_DECOMPOSE
Color c(0.4,0.9,0.1);
for(int i=0;i<decomp.size();i++) {
c.set_hsv( Math::fmod(c.get_h() + 0.738,1),c.get_s(),c.get_v(),0.5);
draw_colored_polygon(decomp[i],c);
}
#endif
} break;
}
}
void CollisionPolygon2D::set_polygon(const Vector<Point2>& p_polygon) {
polygon=p_polygon;
for(int i=0;i<polygon.size();i++) {
if (i==0)
aabb=Rect2(polygon[i],Size2());
else
aabb.expand_to(polygon[i]);
}
if (aabb==Rect2()) {
aabb=Rect2(-10,-10,20,20);
} else {
aabb.pos-=aabb.size*0.3;
aabb.size+=aabb.size*0.6;
}
_update_parent();
update();
}
Vector<Point2> CollisionPolygon2D::get_polygon() const {
return polygon;
}
void CollisionPolygon2D::set_build_mode(BuildMode p_mode) {
ERR_FAIL_INDEX(p_mode,2);
build_mode=p_mode;
}
CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const{
return build_mode;
}
Rect2 CollisionPolygon2D::get_item_rect() const {
return aabb;
}
void CollisionPolygon2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon2D::_add_to_collision_object);
ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&CollisionPolygon2D::set_polygon);
ObjectTypeDB::bind_method(_MD("get_polygon"),&CollisionPolygon2D::get_polygon);
ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon2D::set_build_mode);
ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon2D::get_build_mode);
ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Automatic,Segments,Solids"),_SCS("set_build_mode"),_SCS("get_build_mode"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon"));
}
CollisionPolygon2D::CollisionPolygon2D() {
aabb=Rect2(-10,-10,20,20);
build_mode=BUILD_SOLIDS;
}

View File

@ -0,0 +1,75 @@
/*************************************************************************/
/* collision_polygon_2d.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_POLYGON_2D_H
#define COLLISION_POLYGON_2D_H
#include "scene/2d/node_2d.h"
#include "scene/resources/shape_2d.h"
class CollisionPolygon2D : public Node2D {
OBJ_TYPE(CollisionPolygon2D,Node2D);
public:
enum BuildMode {
BUILD_SOLIDS,
BUILD_SEGMENTS,
};
protected:
Rect2 aabb;
BuildMode build_mode;
Vector<Point2> polygon;
void _add_to_collision_object(Object *p_obj);
void _update_parent();
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void set_build_mode(BuildMode p_mode);
BuildMode get_build_mode() const;
void set_polygon(const Vector<Point2>& p_polygon);
Vector<Point2> get_polygon() const;
virtual Rect2 get_item_rect() const;
CollisionPolygon2D();
};
VARIANT_ENUM_CAST( CollisionPolygon2D::BuildMode );
#endif // COLLISION_POLYGON_2D_H

View File

@ -0,0 +1,248 @@
/*************************************************************************/
/* collision_shape_2d.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_shape_2d.h"
#include "collision_object_2d.h"
#include "scene/resources/segment_shape_2d.h"
#include "scene/resources/shape_line_2d.h"
#include "scene/resources/circle_shape_2d.h"
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/capsule_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
void CollisionShape2D::_add_to_collision_object(Object *p_obj) {
CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>();
ERR_FAIL_COND(!co);
co->add_shape(shape,get_transform());
if (trigger)
co->set_shape_as_trigger(co->get_shape_count()-1,true);
}
void CollisionShape2D::_shape_changed() {
update();
_update_parent();
}
void CollisionShape2D::_update_parent() {
Node *parent = get_parent();
if (!parent)
return;
CollisionObject2D *co = parent->cast_to<CollisionObject2D>();
if (!co)
return;
co->_update_shapes_from_children();
}
void CollisionShape2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (!is_inside_scene())
break;
_update_parent();
} break;
/*
case NOTIFICATION_TRANSFORM_CHANGED: {
if (!is_inside_scene())
break;
_update_parent();
} break;*/
case NOTIFICATION_DRAW: {
rect=Rect2();
Color draw_col=Color(0,0.6,0.7,0.5);
if (shape->cast_to<LineShape2D>()) {
LineShape2D *l = shape->cast_to<LineShape2D>();
Vector2 point = l->get_d() * l->get_normal();
Vector2 l1[2]={point-l->get_normal().tangent()*100,point+l->get_normal().tangent()*100};
draw_line(l1[0],l1[1],draw_col,3);
Vector2 l2[2]={point,point+l->get_normal()*30};
draw_line(l2[0],l2[1],draw_col,3);
rect.pos=l1[0];
rect.expand_to(l1[1]);
rect.expand_to(l2[0]);
rect.expand_to(l2[1]);
} else if (shape->cast_to<SegmentShape2D>()) {
SegmentShape2D *s = shape->cast_to<SegmentShape2D>();
draw_line(s->get_a(),s->get_b(),draw_col,3);
rect.pos=s->get_a();
rect.expand_to(s->get_b());
} else if (shape->cast_to<RayShape2D>()) {
RayShape2D *s = shape->cast_to<RayShape2D>();
Vector2 tip = Vector2(0,s->get_length());
draw_line(Vector2(),tip,draw_col,3);
Vector<Vector2> pts;
float tsize=4;
pts.push_back(tip+Vector2(0,tsize));
pts.push_back(tip+Vector2(0.707*tsize,0));
pts.push_back(tip+Vector2(-0.707*tsize,0));
Vector<Color> cols;
for(int i=0;i<3;i++)
cols.push_back(draw_col);
draw_primitive(pts,cols,Vector<Vector2>()); //small arrow
rect.pos=Vector2();
rect.expand_to(tip);
rect=rect.grow(0.707*tsize);
} else if (shape->cast_to<CircleShape2D>()) {
CircleShape2D *s = shape->cast_to<CircleShape2D>();
Vector<Vector2> points;
for(int i=0;i<24;i++) {
points.push_back(Vector2(Math::cos(i*Math_PI*2/24.0),Math::sin(i*Math_PI*2/24.0))*s->get_radius());
}
draw_colored_polygon(points,draw_col);
rect.pos=-Point2(s->get_radius(),s->get_radius());
rect.size=Point2(s->get_radius(),s->get_radius())*2.0;
} else if (shape->cast_to<RectangleShape2D>()) {
RectangleShape2D *s = shape->cast_to<RectangleShape2D>();
Vector2 he = s->get_extents();
rect=Rect2(-he,he*2.0);
draw_rect(rect,draw_col);;
} else if (shape->cast_to<CapsuleShape2D>()) {
CapsuleShape2D *s = shape->cast_to<CapsuleShape2D>();
Vector<Vector2> points;
for(int i=0;i<24;i++) {
Vector2 ofs = Vector2(0,(i>6 && i<=18) ? -s->get_height()*0.5 : s->get_height()*0.5);
points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*s->get_radius() + ofs);
if (i==6 || i==18)
points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*s->get_radius() - ofs);
}
draw_colored_polygon(points,draw_col);
Vector2 he=Point2(s->get_radius(),s->get_radius()+s->get_height()*0.5);
rect.pos=-he;
rect.size=he*2.0;
} else if (shape->cast_to<ConvexPolygonShape2D>()) {
ConvexPolygonShape2D *s = shape->cast_to<ConvexPolygonShape2D>();
Vector<Vector2> points = s->get_points();
for(int i=0;i<points.size();i++) {
if (i==0)
rect.pos=points[i];
else
rect.expand_to(points[i]);
}
draw_colored_polygon(points,draw_col);
}
rect=rect.grow(3);
} break;
}
}
void CollisionShape2D::set_shape(const Ref<Shape2D>& p_shape) {
if (shape.is_valid())
shape->disconnect("changed",this,"_shape_changed");
shape=p_shape;
update();
_update_parent();
if (shape.is_valid())
shape->connect("changed",this,"_shape_changed");
}
Ref<Shape2D> CollisionShape2D::get_shape() const {
return shape;
}
Rect2 CollisionShape2D::get_item_rect() const {
return rect;
}
void CollisionShape2D::set_trigger(bool p_trigger) {
trigger=p_trigger;
_update_parent();
}
bool CollisionShape2D::is_trigger() const{
return trigger;
}
void CollisionShape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_shape","shape"),&CollisionShape2D::set_shape);
ObjectTypeDB::bind_method(_MD("get_shape"),&CollisionShape2D::get_shape);
ObjectTypeDB::bind_method(_MD("_shape_changed"),&CollisionShape2D::_shape_changed);
ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionShape2D::_add_to_collision_object);
ObjectTypeDB::bind_method(_MD("set_trigger","enable"),&CollisionShape2D::set_trigger);
ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionShape2D::is_trigger);
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D"),_SCS("set_shape"),_SCS("get_shape"));
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger"));
}
CollisionShape2D::CollisionShape2D() {
rect=Rect2(-Point2(10,10),Point2(20,20));
trigger=false;
}

View File

@ -0,0 +1,61 @@
/*************************************************************************/
/* collision_shape_2d.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_2D_H
#define COLLISION_SHAPE_2D_H
#include "scene/2d/node_2d.h"
#include "scene/resources/shape_2d.h"
class CollisionShape2D : public Node2D {
OBJ_TYPE(CollisionShape2D,Node2D);
Ref<Shape2D> shape;
Rect2 rect;
bool trigger;
void _shape_changed();
protected:
void _update_parent();
void _notification(int p_what);
static void _bind_methods();
void _add_to_collision_object(Object *p_obj);
public:
void set_shape(const Ref<Shape2D>& p_shape);
Ref<Shape2D> get_shape() const;
virtual Rect2 get_item_rect() const;
void set_trigger(bool p_trigger);
bool is_trigger() const;
CollisionShape2D();
};
#endif // COLLISION_SHAPE_2D_H

412
scene/2d/joints_2d.cpp Normal file
View File

@ -0,0 +1,412 @@
/*************************************************************************/
/* joints_2d.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 "joints_2d.h"
#include "servers/physics_2d_server.h"
#include "physics_body_2d.h"
void Joint2D::_update_joint() {
if (!is_inside_scene())
return;
if (joint.is_valid()) {
Physics2DServer::get_singleton()->free(joint);
}
joint=RID();
joint = _configure_joint();
Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint,Physics2DServer::JOINT_PARAM_BIAS,bias);
}
void Joint2D::set_node_a(const NodePath& p_node_a) {
if (a==p_node_a)
return;
a=p_node_a;
_update_joint();
}
NodePath Joint2D::get_node_a() const{
return a;
}
void Joint2D::set_node_b(const NodePath& p_node_b){
if (b==p_node_b)
return;
b=p_node_b;
_update_joint();
}
NodePath Joint2D::get_node_b() const{
return b;
}
void Joint2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_READY: {
_update_joint();
} break;
case NOTIFICATION_EXIT_SCENE: {
if (joint.is_valid()) {
Physics2DServer::get_singleton()->free(joint);
joint=RID();
}
} break;
}
}
void Joint2D::set_bias(real_t p_bias) {
bias=p_bias;
if (joint.is_valid())
Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint,Physics2DServer::JOINT_PARAM_BIAS,bias);
}
real_t Joint2D::get_bias() const{
return bias;
}
void Joint2D::_bind_methods() {
ObjectTypeDB::bind_method( _MD("set_node_a","node"), &Joint2D::set_node_a );
ObjectTypeDB::bind_method( _MD("get_node_a"), &Joint2D::get_node_a );
ObjectTypeDB::bind_method( _MD("set_node_b","node"), &Joint2D::set_node_b );
ObjectTypeDB::bind_method( _MD("get_node_b"), &Joint2D::get_node_b );
ObjectTypeDB::bind_method( _MD("set_bias","bias"), &Joint2D::set_bias );
ObjectTypeDB::bind_method( _MD("get_bias"), &Joint2D::get_bias );
ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "node_a"), _SCS("set_node_a"),_SCS("get_node_a") );
ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "node_b"), _SCS("set_node_b"),_SCS("get_node_b") );
ADD_PROPERTY( PropertyInfo( Variant::REAL, "bias/bias",PROPERTY_HINT_RANGE,"0,0.9,0.01"), _SCS("set_bias"),_SCS("get_bias") );
}
Joint2D::Joint2D() {
bias=0;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void PinJoint2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
if (is_inside_scene() && get_scene()->is_editor_hint()) {
draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3);
draw_line(Point2(0,-10),Point2(0,+10),Color(0.7,0.6,0.0,0.5),3);
}
} break;
}
}
RID PinJoint2D::_configure_joint() {
Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL;
Node *node_b = has_node( get_node_b() ) ? get_node( get_node_b() ) : (Node*)NULL;
if (!node_a && !node_b)
return RID();
PhysicsBody2D *body_a=node_a ? node_a->cast_to<PhysicsBody2D>() : (PhysicsBody2D*)NULL;
PhysicsBody2D *body_b=node_b ? node_b->cast_to<PhysicsBody2D>() : (PhysicsBody2D*)NULL;
if (!body_a && !body_b)
return RID();
if (!body_a) {
SWAP(body_a,body_b);
} else if (body_b) {
//add a collision exception between both
Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
}
return Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(),body_a->get_rid(),body_b?body_b->get_rid():RID());
}
PinJoint2D::PinJoint2D() {
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void GrooveJoint2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
if (is_inside_scene() && get_scene()->is_editor_hint()) {
draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3);
draw_line(Point2(-10,length),Point2(+10,length),Color(0.7,0.6,0.0,0.5),3);
draw_line(Point2(0,0),Point2(0,length),Color(0.7,0.6,0.0,0.5),3);
draw_line(Point2(-10,initial_offset),Point2(+10,initial_offset),Color(0.8,0.8,0.9,0.5),5);
}
} break;
}
}
RID GrooveJoint2D::_configure_joint(){
Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL;
Node *node_b = has_node( get_node_b() ) ? get_node( get_node_b() ) : (Node*)NULL;
if (!node_a || !node_b)
return RID();
PhysicsBody2D *body_a=node_a->cast_to<PhysicsBody2D>();
PhysicsBody2D *body_b=node_b->cast_to<PhysicsBody2D>();
if (!body_a || !body_b)
return RID();
Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
Matrix32 gt = get_global_transform();
Vector2 groove_A1 = gt.get_origin();
Vector2 groove_A2 = gt.xform( Vector2(0,length) );
Vector2 anchor_B = gt.xform( Vector2(0,initial_offset) );
return Physics2DServer::get_singleton()->groove_joint_create(groove_A1,groove_A2,anchor_B,body_a->get_rid(),body_b->get_rid());
}
void GrooveJoint2D::set_length(real_t p_length) {
length=p_length;
update();
}
real_t GrooveJoint2D::get_length() const {
return length;
}
void GrooveJoint2D::set_initial_offset(real_t p_initial_offset) {
initial_offset=p_initial_offset;
update();
}
real_t GrooveJoint2D::get_initial_offset() const {
return initial_offset;
}
void GrooveJoint2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_length","length"),&GrooveJoint2D::set_length);
ObjectTypeDB::bind_method(_MD("get_length"),&GrooveJoint2D::get_length);
ObjectTypeDB::bind_method(_MD("set_initial_offset","offset"),&GrooveJoint2D::set_initial_offset);
ObjectTypeDB::bind_method(_MD("get_initial_offset"),&GrooveJoint2D::get_initial_offset);
ADD_PROPERTY( PropertyInfo( Variant::REAL, "length", PROPERTY_HINT_EXP_RANGE,"1,65535,1"), _SCS("set_length"),_SCS("get_length"));
ADD_PROPERTY( PropertyInfo( Variant::REAL, "initial_offset", PROPERTY_HINT_EXP_RANGE,"1,65535,1"), _SCS("set_initial_offset"),_SCS("get_initial_offset"));
}
GrooveJoint2D::GrooveJoint2D() {
length=50;
initial_offset=25;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void DampedSpringJoint2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
if (is_inside_scene() && get_scene()->is_editor_hint()) {
draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3);
draw_line(Point2(-10,length),Point2(+10,length),Color(0.7,0.6,0.0,0.5),3);
draw_line(Point2(0,0),Point2(0,length),Color(0.7,0.6,0.0,0.5),3);
}
} break;
}
}
RID DampedSpringJoint2D::_configure_joint(){
Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL;
Node *node_b = has_node( get_node_b() ) ? get_node( get_node_b() ) : (Node*)NULL;
if (!node_a || !node_b)
return RID();
PhysicsBody2D *body_a=node_a->cast_to<PhysicsBody2D>();
PhysicsBody2D *body_b=node_b->cast_to<PhysicsBody2D>();
if (!body_a || !body_b)
return RID();
Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
Matrix32 gt = get_global_transform();
Vector2 anchor_A = gt.get_origin();
Vector2 anchor_B = gt.xform( Vector2(0,length) );
RID dsj = Physics2DServer::get_singleton()->damped_spring_joint_create(anchor_A,anchor_B,body_a->get_rid(),body_b->get_rid());
if (rest_length)
Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj,Physics2DServer::DAMPED_STRING_REST_LENGTH,rest_length);
Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj,Physics2DServer::DAMPED_STRING_STIFFNESS,stiffness);
Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj,Physics2DServer::DAMPED_STRING_DAMPING,damping);
return dsj;
}
void DampedSpringJoint2D::set_length(real_t p_length) {
length=p_length;
update();
}
real_t DampedSpringJoint2D::get_length() const {
return length;
}
void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) {
rest_length=p_rest_length;
update();
if (get_joint().is_valid())
Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(),Physics2DServer::DAMPED_STRING_REST_LENGTH,p_rest_length?p_rest_length:length);
}
real_t DampedSpringJoint2D::get_rest_length() const {
return rest_length;
}
void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) {
stiffness=p_stiffness;
update();
if (get_joint().is_valid())
Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(),Physics2DServer::DAMPED_STRING_STIFFNESS,p_stiffness);
}
real_t DampedSpringJoint2D::get_stiffness() const {
return stiffness;
}
void DampedSpringJoint2D::set_damping(real_t p_damping) {
damping=p_damping;
update();
if (get_joint().is_valid())
Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(),Physics2DServer::DAMPED_STRING_DAMPING,p_damping);
}
real_t DampedSpringJoint2D::get_damping() const {
return damping;
}
void DampedSpringJoint2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_length","length"),&DampedSpringJoint2D::set_length);
ObjectTypeDB::bind_method(_MD("get_length"),&DampedSpringJoint2D::get_length);
ObjectTypeDB::bind_method(_MD("set_rest_length","rest_length"),&DampedSpringJoint2D::set_rest_length);
ObjectTypeDB::bind_method(_MD("get_rest_length"),&DampedSpringJoint2D::get_rest_length);
ObjectTypeDB::bind_method(_MD("set_stiffness","stiffness"),&DampedSpringJoint2D::set_stiffness);
ObjectTypeDB::bind_method(_MD("get_stiffness"),&DampedSpringJoint2D::get_stiffness);
ObjectTypeDB::bind_method(_MD("set_damping","damping"),&DampedSpringJoint2D::set_damping);
ObjectTypeDB::bind_method(_MD("get_damping"),&DampedSpringJoint2D::get_damping);
ADD_PROPERTY( PropertyInfo( Variant::REAL, "length", PROPERTY_HINT_EXP_RANGE,"1,65535,1"), _SCS("set_length"),_SCS("get_length"));
ADD_PROPERTY( PropertyInfo( Variant::REAL, "rest_length", PROPERTY_HINT_EXP_RANGE,"0,65535,1"), _SCS("set_rest_length"),_SCS("get_rest_length"));
ADD_PROPERTY( PropertyInfo( Variant::REAL, "stiffness", PROPERTY_HINT_EXP_RANGE,"0.1,64,0.1"), _SCS("set_stiffness"),_SCS("get_stiffness"));
ADD_PROPERTY( PropertyInfo( Variant::REAL, "damping", PROPERTY_HINT_EXP_RANGE,"0.01,16,0.01"), _SCS("set_damping"),_SCS("get_damping"));
}
DampedSpringJoint2D::DampedSpringJoint2D() {
length=50;
rest_length=0;
stiffness=20;
damping=1;
}

141
scene/2d/joints_2d.h Normal file
View File

@ -0,0 +1,141 @@
/*************************************************************************/
/* joints_2d.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 JOINTS_2D_H
#define JOINTS_2D_H
#include "node_2d.h"
class Joint2D : public Node2D {
OBJ_TYPE(Joint2D,Node2D);
RID joint;
NodePath a;
NodePath b;
real_t bias;
protected:
void _update_joint();
void _notification(int p_what);
virtual RID _configure_joint()=0;
static void _bind_methods();
public:
void set_node_a(const NodePath& p_node_a);
NodePath get_node_a() const;
void set_node_b(const NodePath& p_node_b);
NodePath get_node_b() const;
void set_bias(real_t p_bias);
real_t get_bias() const;
RID get_joint() const { return joint; }
Joint2D();
};
class PinJoint2D : public Joint2D {
OBJ_TYPE(PinJoint2D,Joint2D);
protected:
void _notification(int p_what);
virtual RID _configure_joint();
public:
PinJoint2D();
};
class GrooveJoint2D : public Joint2D {
OBJ_TYPE(GrooveJoint2D,Joint2D);
real_t length;
real_t initial_offset;
protected:
void _notification(int p_what);
virtual RID _configure_joint();
static void _bind_methods();
public:
void set_length(real_t p_length);
real_t get_length() const;
void set_initial_offset(real_t p_initial_offset);
real_t get_initial_offset() const;
GrooveJoint2D();
};
class DampedSpringJoint2D : public Joint2D {
OBJ_TYPE(DampedSpringJoint2D,Joint2D);
real_t stiffness;
real_t damping;
real_t rest_length;
real_t length;
protected:
void _notification(int p_what);
virtual RID _configure_joint();
static void _bind_methods();
public:
void set_length(real_t p_length);
real_t get_length() const;
void set_rest_length(real_t p_rest_length);
real_t get_rest_length() const;
void set_damping(real_t p_damping);
real_t get_damping() const;
void set_stiffness(real_t p_stiffness);
real_t get_stiffness() const;
DampedSpringJoint2D();
};
#endif // JOINTS_2D_H

291
scene/2d/node_2d.cpp Normal file
View File

@ -0,0 +1,291 @@
/*************************************************************************/
/* node_2d.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 "node_2d.h"
#include "servers/visual_server.h"
#include "scene/gui/control.h"
#include "scene/main/viewport.h"
#include "message_queue.h"
void Node2D::edit_set_pivot(const Point2& p_pivot) {
}
Point2 Node2D::edit_get_pivot() const {
return Point2();
}
bool Node2D::edit_has_pivot() const {
return false;
}
Variant Node2D::edit_get_state() const {
Array state;
state.push_back(pos);
state.push_back(angle);
state.push_back(scale);
return state;
}
void Node2D::edit_set_state(const Variant& p_state) {
Array state = p_state;
ERR_FAIL_COND( state.size() != 3);
pos = state[0];
angle = state[1];
scale = state[2];
_update_transform();
_change_notify("transform/rot");
_change_notify("transform/scale");
_change_notify("transform/pos");
}
void Node2D::edit_set_rect(const Rect2& p_edit_rect) {
Rect2 r = get_item_rect();
Vector2 zero_offset;
if (r.size.x!=0)
zero_offset.x = -r.pos.x / r.size.x;
if (r.size.y!=0)
zero_offset.y = -r.pos.y / r.size.y;
Size2 new_scale(1,1);
if (r.size.x!=0)
new_scale.x = p_edit_rect.size.x / r.size.x;
if (r.size.y!=0)
new_scale.y = p_edit_rect.size.y / r.size.y;
Point2 new_pos = p_edit_rect.pos + p_edit_rect.size*zero_offset;//p_edit_rect.pos - r.pos;
Matrix32 postxf;
postxf.set_rotation_and_scale(angle,scale);
new_pos = postxf.xform(new_pos);
pos+=new_pos;
scale*=new_scale;
_update_transform();
_change_notify("transform/scale");
_change_notify("transform/pos");
}
void Node2D::edit_rotate(float p_rot) {
angle+=p_rot;
_update_transform();
_change_notify("transform/rot");
}
void Node2D::_update_xform_values() {
pos=_mat.elements[2];
angle=_mat.get_rotation();
scale=_mat.get_scale();
_xform_dirty=false;
}
void Node2D::_update_transform() {
Matrix32 mat(angle,pos);
_mat.set_rotation_and_scale(angle,scale);
_mat.elements[2]=pos;
VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),_mat);
if (!is_inside_scene())
return;
_notify_transform();
}
void Node2D::set_pos(const Point2& p_pos) {
if (_xform_dirty)
((Node2D*)this)->_update_xform_values();
pos=p_pos;
_update_transform();
_change_notify("transform/pos");
}
void Node2D::set_rot(float p_angle) {
if (_xform_dirty)
((Node2D*)this)->_update_xform_values();
angle=p_angle;
_update_transform();
_change_notify("transform/rot");
}
void Node2D::set_scale(const Size2& p_scale) {
if (_xform_dirty)
((Node2D*)this)->_update_xform_values();
scale=p_scale;
_update_transform();
_change_notify("transform/scale");
}
Point2 Node2D::get_pos() const {
if (_xform_dirty)
((Node2D*)this)->_update_xform_values();
return pos;
}
float Node2D::get_rot() const {
if (_xform_dirty)
((Node2D*)this)->_update_xform_values();
return angle;
}
Size2 Node2D::get_scale() const {
if (_xform_dirty)
((Node2D*)this)->_update_xform_values();
return scale;
}
void Node2D::_set_rotd(float p_angle) {
set_rot(Math::deg2rad(p_angle));
}
float Node2D::_get_rotd() const {
return Math::rad2deg(get_rot());
}
void Node2D::_notification(int p_what) {
switch(p_what) {
}
}
Matrix32 Node2D::get_transform() const {
return _mat;
}
Rect2 Node2D::get_item_rect() const {
if (get_script_instance()) {
Variant::CallError err;
Rect2 r = get_script_instance()->call("_get_item_rect",NULL,0,err);
if (err.error==Variant::CallError::CALL_OK)
return r;
}
return Rect2(Point2(-32,-32),Size2(64,64));
}
Point2 Node2D::get_global_pos() const {
return get_global_transform().get_origin();
}
void Node2D::set_transform(const Matrix32& p_transform) {
_mat=p_transform;
_xform_dirty=true;
VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),_mat);
if (!is_inside_scene())
return;
_notify_transform();
}
void Node2D::set_global_transform(const Matrix32& p_transform) {
CanvasItem *pi = get_parent_item();
if (pi)
set_transform( pi->get_global_transform().affine_inverse() * p_transform);
else
set_transform(p_transform);
}
void Node2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_get_rotd"),&Node2D::_get_rotd);
ObjectTypeDB::bind_method(_MD("_set_rotd"),&Node2D::_set_rotd);
ObjectTypeDB::bind_method(_MD("set_pos","pos"),&Node2D::set_pos);
ObjectTypeDB::bind_method(_MD("set_rot","rot"),&Node2D::set_rot);
ObjectTypeDB::bind_method(_MD("set_scale","scale"),&Node2D::set_scale);
ObjectTypeDB::bind_method(_MD("get_pos"),&Node2D::get_pos);
ObjectTypeDB::bind_method(_MD("get_rot"),&Node2D::get_rot);
ObjectTypeDB::bind_method(_MD("get_scale"),&Node2D::get_scale);
ObjectTypeDB::bind_method(_MD("get_global_pos"),&Node2D::get_global_pos);
ObjectTypeDB::bind_method(_MD("set_transform","xform"),&Node2D::set_transform);
ObjectTypeDB::bind_method(_MD("set_global_transform","xform"),&Node2D::set_global_transform);
ObjectTypeDB::bind_method(_MD("edit_set_pivot"),&Node2D::edit_set_pivot);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos"));
ADD_PROPERTY(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd"));
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale"));
}
Node2D::Node2D() {
angle=0;
scale=Vector2(1,1);
_xform_dirty=false;
}

89
scene/2d/node_2d.h Normal file
View File

@ -0,0 +1,89 @@
/*************************************************************************/
/* node_2d.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 NODE2D_H
#define NODE2D_H
#include "scene/2d/canvas_item.h"
class Node2D : public CanvasItem {
OBJ_TYPE(Node2D, CanvasItem );
Point2 pos;
float angle;
Size2 scale;
Matrix32 _mat;
bool _xform_dirty;
void _update_transform();
void _set_rotd(float p_angle);
float _get_rotd() const;
void _update_xform_values();
protected:
void _notification(int p_what);
static void _bind_methods();
public:
virtual Variant edit_get_state() const;
virtual void edit_set_state(const Variant& p_state);
virtual void edit_set_rect(const Rect2& p_edit_rect);
virtual void edit_rotate(float p_rot);
virtual void edit_set_pivot(const Point2& p_pivot);
virtual Point2 edit_get_pivot() const;
virtual bool edit_has_pivot() const;
void set_pos(const Point2& p_pos);
void set_rot(float p_angle);
void set_scale(const Size2& p_scale);
Point2 get_pos() const;
float get_rot() const;
Size2 get_scale() const;
Point2 get_global_pos() const;
virtual Rect2 get_item_rect() const;
void set_transform(const Matrix32& p_transform);
void set_global_transform(const Matrix32& p_transform);
Matrix32 get_transform() const;
Node2D();
};
#endif // NODE2D_H

View File

@ -0,0 +1,30 @@
/*************************************************************************/
/* node_2d_singleton.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 "node_2d_singleton.h"

View File

@ -0,0 +1,33 @@
/*************************************************************************/
/* node_2d_singleton.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 NODE_2D_SINGLETON_H
#define NODE_2D_SINGLETON_H
#endif // NODE_2D_SINGLETON_H

View File

@ -0,0 +1,200 @@
/*************************************************************************/
/* parallax_background.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 "parallax_background.h"
#include "parallax_layer.h"
void ParallaxBackground::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_SCENE: {
group_name = "__cameras_"+itos(get_viewport().get_id());
add_to_group(group_name);
} break;
case NOTIFICATION_EXIT_SCENE: {
remove_from_group(group_name);
} break;
}
}
void ParallaxBackground::_camera_moved(const Matrix32& p_transform) {
set_scroll_offset(p_transform.get_origin());
set_scroll_scale(p_transform.get_scale().dot(Vector2(0.5,0.5)));
}
void ParallaxBackground::set_scroll_scale(float p_scale) {
scale=p_scale;
}
float ParallaxBackground::get_scroll_scale() const{
return scale;
}
void ParallaxBackground::set_scroll_offset(const Point2& p_ofs) {
offset=p_ofs;
_update_scroll();
}
void ParallaxBackground::_update_scroll() {
if (!is_inside_scene())
return;
Vector2 ofs = base_offset+offset*base_scale;
Size2 vps = get_viewport_size();
ofs = -ofs;
if (limit_begin.x < limit_end.x) {
if (ofs.x < limit_begin.x)
ofs.x=limit_begin.x;
else if (ofs.x+vps.x > limit_end.x)
ofs.x=limit_end.x-vps.x;
}
if (limit_begin.y < limit_end.y) {
if (ofs.y < limit_begin.y)
ofs.y=limit_begin.y;
else if (ofs.y+vps.y > limit_end.y)
ofs.y=limit_end.y-vps.y;
}
ofs = -ofs;
for(int i=0;i<get_child_count();i++) {
ParallaxLayer *l=get_child(i)->cast_to<ParallaxLayer>();
if (!l)
continue;
l->set_base_offset_and_scale(ofs,scale);
}
}
Point2 ParallaxBackground::get_scroll_offset() const {
return offset;
}
void ParallaxBackground::set_scroll_base_offset(const Point2& p_ofs) {
base_offset=p_ofs;
_update_scroll();
}
Point2 ParallaxBackground::get_scroll_base_offset() const{
return base_offset;
}
void ParallaxBackground::set_scroll_base_scale(const Point2& p_ofs) {
base_scale=p_ofs;
_update_scroll();
}
Point2 ParallaxBackground::get_scroll_base_scale() const{
return base_scale;
}
void ParallaxBackground::set_limit_begin(const Point2& p_ofs) {
limit_begin=p_ofs;
_update_scroll();
}
Point2 ParallaxBackground::get_limit_begin() const {
return limit_begin;
}
void ParallaxBackground::set_limit_end(const Point2& p_ofs) {
limit_end=p_ofs;
_update_scroll();
}
Point2 ParallaxBackground::get_limit_end() const {
return limit_end;
}
void ParallaxBackground::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_camera_moved"),&ParallaxBackground::_camera_moved);
ObjectTypeDB::bind_method(_MD("set_scroll_offset","ofs"),&ParallaxBackground::set_scroll_offset);
ObjectTypeDB::bind_method(_MD("get_scroll_offset"),&ParallaxBackground::get_scroll_offset);
ObjectTypeDB::bind_method(_MD("set_scroll_base_offset","ofs"),&ParallaxBackground::set_scroll_base_offset);
ObjectTypeDB::bind_method(_MD("get_scroll_base_offset"),&ParallaxBackground::get_scroll_base_offset);
ObjectTypeDB::bind_method(_MD("set_scroll_base_scale","scale"),&ParallaxBackground::set_scroll_base_scale);
ObjectTypeDB::bind_method(_MD("get_scroll_base_scale"),&ParallaxBackground::get_scroll_base_scale);
ObjectTypeDB::bind_method(_MD("set_limit_begin","ofs"),&ParallaxBackground::set_limit_begin);
ObjectTypeDB::bind_method(_MD("get_limit_begin"),&ParallaxBackground::get_limit_begin);
ObjectTypeDB::bind_method(_MD("set_limit_end","ofs"),&ParallaxBackground::set_limit_end);
ObjectTypeDB::bind_method(_MD("get_limit_end"),&ParallaxBackground::get_limit_end);
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/offset"),_SCS("set_scroll_offset"),_SCS("get_scroll_offset"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/base_offset"),_SCS("set_scroll_base_offset"),_SCS("get_scroll_base_offset"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/base_scale"),_SCS("set_scroll_base_scale"),_SCS("get_scroll_base_scale"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_begin"),_SCS("set_limit_begin"),_SCS("get_limit_begin"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_end"),_SCS("set_limit_end"),_SCS("get_limit_end"));
}
ParallaxBackground::ParallaxBackground() {
base_scale=Vector2(1,1);
scale=1.0;
set_layer(-1); //behind all by default
}

View File

@ -0,0 +1,78 @@
/*************************************************************************/
/* parallax_background.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 PARALLAX_BACKGROUND_H
#define PARALLAX_BACKGROUND_H
#include "scene/main/canvas_layer.h"
#include "scene/2d/node_2d.h"
#include "scene/2d/camera_2d.h"
class ParallaxBackground : public CanvasLayer {
OBJ_TYPE( ParallaxBackground, CanvasLayer );
Point2 offset;
float scale;
Point2 base_offset;
Point2 base_scale;
String group_name;
Point2 limit_begin;
Point2 limit_end;
void _update_scroll();
protected:
void _camera_moved(const Matrix32& p_transform);
void _notification(int p_what);
static void _bind_methods();
public:
void set_scroll_offset(const Point2& p_ofs);
Point2 get_scroll_offset() const;
void set_scroll_scale(float p_ofs);
float get_scroll_scale() const;
void set_scroll_base_offset(const Point2& p_ofs);
Point2 get_scroll_base_offset() const;
void set_scroll_base_scale(const Point2& p_ofs);
Point2 get_scroll_base_scale() const;
void set_limit_begin(const Point2& p_ofs);
Point2 get_limit_begin() const;
void set_limit_end(const Point2& p_ofs);
Point2 get_limit_end() const;
ParallaxBackground();
};
#endif // PARALLAX_BACKGROUND_H

138
scene/2d/parallax_layer.cpp Normal file
View File

@ -0,0 +1,138 @@
/*************************************************************************/
/* parallax_layer.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 "parallax_layer.h"
#include "parallax_background.h"
void ParallaxLayer::set_motion_scale(const Size2& p_scale) {
motion_scale=p_scale;
}
Size2 ParallaxLayer::get_motion_scale() const {
return motion_scale;
}
void ParallaxLayer::_update_mirroring() {
if (!get_parent())
return;
ParallaxBackground *pb = get_parent()->cast_to<ParallaxBackground>();
if (pb) {
RID c = pb->get_world_2d()->get_canvas();
RID ci = get_canvas_item();
VisualServer::get_singleton()->canvas_set_item_mirroring(c,ci,mirroring);
}
}
void ParallaxLayer::set_mirroring(const Size2& p_mirroring) {
mirroring=p_mirroring;
_update_mirroring();
}
Size2 ParallaxLayer::get_mirroring() const{
return mirroring;
}
void ParallaxLayer::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_SCENE: {
orig_offset=get_pos();
orig_scale=get_scale();
_update_mirroring();
} break;
}
}
void ParallaxLayer::set_base_offset_and_scale(const Point2& p_offset,float p_scale) {
if (!is_inside_scene())
return;
if (get_scene()->is_editor_hint())
return;
Point2 new_ofs = ((orig_offset+p_offset)*motion_scale)*p_scale;
if (mirroring.x) {
while( new_ofs.x>=0) {
new_ofs.x -= mirroring.x*p_scale;
}
while(new_ofs.x < -mirroring.x*p_scale) {
new_ofs.x += mirroring.x*p_scale;
}
}
if (mirroring.y) {
while( new_ofs.y>=0) {
new_ofs.y -= mirroring.y*p_scale;
}
while(new_ofs.y < -mirroring.y*p_scale) {
new_ofs.y += mirroring.y*p_scale;
}
}
set_pos(new_ofs);
set_scale(Vector2(1,1)*p_scale);
}
void ParallaxLayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_motion_scale","scale"),&ParallaxLayer::set_motion_scale);
ObjectTypeDB::bind_method(_MD("get_motion_scale"),&ParallaxLayer::get_motion_scale);
ObjectTypeDB::bind_method(_MD("set_mirroring","mirror"),&ParallaxLayer::set_mirroring);
ObjectTypeDB::bind_method(_MD("get_mirroring"),&ParallaxLayer::get_mirroring);
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"motion/scale"),_SCS("set_motion_scale"),_SCS("get_motion_scale"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"motion/mirroring"),_SCS("set_mirroring"),_SCS("get_mirroring"));
}
ParallaxLayer::ParallaxLayer()
{
motion_scale=Size2(1,1);
}

62
scene/2d/parallax_layer.h Normal file
View File

@ -0,0 +1,62 @@
/*************************************************************************/
/* parallax_layer.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 PARALLAX_LAYER_H
#define PARALLAX_LAYER_H
#include "scene/2d/node_2d.h"
class ParallaxLayer : public Node2D {
OBJ_TYPE( ParallaxLayer, Node2D );
Point2 orig_offset;
Point2 orig_scale;
Size2 motion_scale;
Vector2 mirroring;
void _update_mirroring();
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void set_motion_scale(const Size2& p_scale);
Size2 get_motion_scale() const;
void set_mirroring(const Size2& p_mirroring);
Size2 get_mirroring() const;
void set_base_offset_and_scale(const Point2& p_offsetf,float p_scale);
ParallaxLayer();
};
#endif // PARALLAX_LAYER_H

1045
scene/2d/particles_2d.cpp Normal file

File diff suppressed because it is too large Load Diff

231
scene/2d/particles_2d.h Normal file
View File

@ -0,0 +1,231 @@
/*************************************************************************/
/* particles_2d.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 PARTICLES_FRAME_H
#define PARTICLES_FRAME_H
#include "scene/2d/node_2d.h"
#include "scene/resources/texture.h"
class Particles2D;
class ParticleAttractor2D : public Node2D {
OBJ_TYPE(ParticleAttractor2D,Node2D);
friend class Particles2D;
bool enabled;
float radius;
float disable_radius;
float gravity;
float absorption;
NodePath path;
Particles2D *owner;
void _update_owner();
void _owner_exited();
void _set_owner(Particles2D* p_owner);
void _notification(int p_what);
static void _bind_methods();
public:
void set_enabled(bool p_enabled);
bool is_enabled() const;
void set_radius(float p_radius);
float get_radius() const;
void set_disable_radius(float p_disable_radius);
float get_disable_radius() const;
void set_gravity(float p_gravity);
float get_gravity() const;
void set_absorption(float p_absorption);
float get_absorption() const;
void set_particles_path(NodePath p_path);
NodePath get_particles_path() const;
ParticleAttractor2D();
};
class Particles2D : public Node2D {
OBJ_TYPE(Particles2D, Node2D);
public:
enum Parameter {
PARAM_DIRECTION,
PARAM_SPREAD,
PARAM_LINEAR_VELOCITY,
PARAM_SPIN_VELOCITY,
PARAM_ORBIT_VELOCITY,
PARAM_GRAVITY_DIRECTION,
PARAM_GRAVITY_STRENGTH,
PARAM_RADIAL_ACCEL,
PARAM_TANGENTIAL_ACCEL,
PARAM_DAMPING,
PARAM_INITIAL_SIZE,
PARAM_FINAL_SIZE,
PARAM_HUE_VARIATION,
PARAM_MAX
};
enum {
MAX_COLOR_PHASES=4
};
private:
float param[PARAM_MAX];
float randomness[PARAM_MAX];
struct Particle {
bool active;
Point2 pos;
Vector2 velocity;
float rot;
uint32_t seed;
Particle() { active=false; seed=123465789; rot=0;}
};
Vector<Particle> particles;
int color_phase_count;
struct ColorPhase {
Color color;
float pos;
} color_phases[MAX_COLOR_PHASES];
struct AttractorCache {
Vector2 pos;
ParticleAttractor2D *attractor;
};
Vector<AttractorCache> attractor_cache;
float explosiveness;
float preprocess;
float lifetime;
bool emitting;
bool local_space;
float emit_timeout;
float time_to_live;
float time_scale;
Point2 emissor_offset;
Vector2 initial_velocity;
Vector2 extents;
DVector<Vector2> emission_points;
float time;
int active_count;
Ref<Texture> texture;
void testee(int a, int b, int c, int d, int e);
void _process_particles(float p_delta);
friend class ParticleAttractor2D;
Set<ParticleAttractor2D*> attractors;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void set_emitting(bool p_emitting);
bool is_emitting() const;
void set_amount(int p_amount);
int get_amount() const;
void set_lifetime(float p_lifetime);
float get_lifetime() const;
void set_time_scale(float p_time_scale);
float get_time_scale() const;
void set_pre_process_time(float p_pre_process_time);
float get_pre_process_time() const;
void set_emit_timeout(float p_timeout);
float get_emit_timeout() const;
void set_emission_half_extents(const Vector2& p_extents);
Vector2 get_emission_half_extents() const;
void set_param(Parameter p_param, float p_value);
float get_param(Parameter p_param) const;
void set_randomness(Parameter p_randomness, float p_value);
float get_randomness(Parameter p_randomness) const;
void set_explosiveness(float p_value);
float get_explosiveness() const;
void set_color_phases(int p_phases);
int get_color_phases() const;
void set_color_phase_color(int p_phase,const Color& p_color);
Color get_color_phase_color(int p_phase) const;
void set_color_phase_pos(int p_phase,float p_pos);
float get_color_phase_pos(int p_phase) const;
void set_texture(const Ref<Texture>& p_texture);
Ref<Texture> get_texture() const;
void set_emissor_offset(const Point2& p_offset);
Point2 get_emissor_offset() const;
void set_use_local_space(bool p_use);
bool is_using_local_space() const;
void set_initial_velocity(const Vector2& p_velocity);
Vector2 get_initial_velocity() const;
void set_emission_points(const DVector<Vector2>& p_points);
DVector<Vector2> get_emission_points() const;
void pre_process(float p_delta);
Particles2D();
};
VARIANT_ENUM_CAST( Particles2D::Parameter );
#endif // PARTICLES_FRAME_H

92
scene/2d/path_2d.cpp Normal file
View File

@ -0,0 +1,92 @@
/*************************************************************************/
/* path_2d.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_2d.h"
void Path2D::_notification(int p_what) {
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;
}
}
}
}
void Path2D::_curve_changed() {
if (is_inside_scene() && get_scene()->is_editor_hint())
update();
}
void Path2D::set_curve(const Ref<Curve2D>& 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");
}
}
Ref<Curve2D> Path2D::get_curve() const{
return curve;
}
void Path2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_curve","curve:Curve2D"),&Path2D::set_curve);
ObjectTypeDB::bind_method(_MD("get_curve:Curve2D","curve"),&Path2D::get_curve);
ObjectTypeDB::bind_method(_MD("_curve_changed"),&Path2D::_curve_changed);
ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve2D"), _SCS("set_curve"),_SCS("get_curve"));
}
Path2D::Path2D() {
set_curve(Ref<Curve2D>( memnew( Curve2D ))); //create one by default
}

57
scene/2d/path_2d.h Normal file
View File

@ -0,0 +1,57 @@
/*************************************************************************/
/* path_2d.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_2D_H
#define PATH_2D_H
#include "scene/resources/curve.h"
#include "scene/2d/node_2d.h"
class Path2D : public Node2D {
OBJ_TYPE( Path2D, Node2D );
Ref<Curve2D> curve;
void _curve_changed();
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void set_curve(const Ref<Curve2D>& p_curve);
Ref<Curve2D> get_curve() const;
Path2D();
};
#endif // PATH_2D_H

View File

@ -0,0 +1,794 @@
/*************************************************************************/
/* physics_body_2d.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_2d.h"
#include "scene/scene_string_names.h"
void PhysicsBody2D::_notification(int p_what) {
/*
switch(p_what) {
case NOTIFICATION_TRANSFORM_CHANGED: {
Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform());
} break;
}
*/
}
PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) : CollisionObject2D( Physics2DServer::get_singleton()->body_create(p_mode), false) {
}
void StaticBody2D::set_constant_linear_velocity(const Vector2& p_vel) {
constant_linear_velocity=p_vel;
Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_LINEAR_VELOCITY,constant_linear_velocity);
}
void StaticBody2D::set_constant_angular_velocity(real_t p_vel) {
constant_angular_velocity=p_vel;
Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_ANGULAR_VELOCITY,constant_angular_velocity);
}
Vector2 StaticBody2D::get_constant_linear_velocity() const {
return constant_linear_velocity;
}
real_t StaticBody2D::get_constant_angular_velocity() const {
return constant_angular_velocity;
}
void StaticBody2D::_state_notify(Object *p_object) {
if (!pre_xform)
return;
Physics2DDirectBodyState *p2d = (Physics2DDirectBodyState*)p_object;
setting=true;
Matrix32 new_xform = p2d->get_transform();
*pre_xform=new_xform;
set_block_transform_notify(true);
set_global_transform(new_xform);
set_block_transform_notify(false);
setting=false;
}
void StaticBody2D::_update_xform() {
if (!pre_xform || !pending)
return;
setting=true;
Matrix32 new_xform = get_global_transform(); //obtain the new one
set_block_transform_notify(true);
Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::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_block_transform_notify(false);
Physics2DServer::get_singleton()->body_static_simulate_motion(get_rid(),new_xform); //then simulate motion!
setting=false;
pending=false;
}
void StaticBody2D::_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 StaticBody2D::set_simulate_motion(bool p_enable) {
if (p_enable==simulating_motion)
return;
simulating_motion=p_enable;
if (p_enable) {
pre_xform = memnew( Matrix32 );
if (is_inside_scene())
*pre_xform=get_transform();
// query = Physics2DServer::get_singleton()->query_create(this,"_state_notify",Variant());
// Physics2DServer::get_singleton()->query_body_direct_state(query,get_rid());
Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_state_notify");
} else {
memdelete( pre_xform );
pre_xform=NULL;
Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(),NULL,StringName());
pending=false;
}
}
bool StaticBody2D::is_simulating_motion() const {
return simulating_motion;
}
void StaticBody2D::set_friction(real_t p_friction){
ERR_FAIL_COND(p_friction<0 || p_friction>1);
friction=p_friction;
Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_FRICTION,friction);
}
real_t StaticBody2D::get_friction() const{
return friction;
}
void StaticBody2D::set_bounce(real_t p_bounce){
ERR_FAIL_COND(p_bounce<0 || p_bounce>1);
bounce=p_bounce;
Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_BOUNCE,bounce);
}
real_t StaticBody2D::get_bounce() const{
return bounce;
}
void StaticBody2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_simulate_motion","enabled"),&StaticBody2D::set_simulate_motion);
ObjectTypeDB::bind_method(_MD("is_simulating_motion"),&StaticBody2D::is_simulating_motion);
ObjectTypeDB::bind_method(_MD("_update_xform"),&StaticBody2D::_update_xform);
ObjectTypeDB::bind_method(_MD("_state_notify"),&StaticBody2D::_state_notify);
ObjectTypeDB::bind_method(_MD("set_constant_linear_velocity","vel"),&StaticBody2D::set_constant_linear_velocity);
ObjectTypeDB::bind_method(_MD("set_constant_angular_velocity","vel"),&StaticBody2D::set_constant_angular_velocity);
ObjectTypeDB::bind_method(_MD("get_constant_linear_velocity"),&StaticBody2D::get_constant_linear_velocity);
ObjectTypeDB::bind_method(_MD("get_constant_angular_velocity"),&StaticBody2D::get_constant_angular_velocity);
ObjectTypeDB::bind_method(_MD("set_friction","friction"),&StaticBody2D::set_friction);
ObjectTypeDB::bind_method(_MD("get_friction"),&StaticBody2D::get_friction);
ObjectTypeDB::bind_method(_MD("set_bounce","bounce"),&StaticBody2D::set_bounce);
ObjectTypeDB::bind_method(_MD("get_bounce"),&StaticBody2D::get_bounce);
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"simulate_motion"),_SCS("set_simulate_motion"),_SCS("is_simulating_motion"));
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"constant_linear_velocity"),_SCS("set_constant_linear_velocity"),_SCS("get_constant_linear_velocity"));
ADD_PROPERTY(PropertyInfo(Variant::REAL,"constant_angular_velocity"),_SCS("set_constant_angular_velocity"),_SCS("get_constant_angular_velocity"));
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"));
}
StaticBody2D::StaticBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_STATIC) {
simulating_motion=false;
pre_xform=NULL;
setting=false;
pending=false;
constant_angular_velocity=0;
bounce=0;
friction=1;
}
StaticBody2D::~StaticBody2D() {
if (pre_xform)
memdelete(pre_xform);
//if (query.is_valid())
// Physics2DServer::get_singleton()->free(query);
}
void RigidBody2D::_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 RigidBody2D::_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 RigidBody2D::_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 _RigidBody2DInOut {
ObjectID id;
int shape;
int local_shape;
};
void RigidBody2D::_direct_state_changed(Object *p_state) {
//eh.. fuck
#ifdef DEBUG_ENABLED
state=p_state->cast_to<Physics2DDirectBodyState>();
#else
state=(Physics2DDirectBodyState*)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++;
}
}
_RigidBody2DInOut *toadd=(_RigidBody2DInOut*)alloca(state->get_contact_count()*sizeof(_RigidBody2DInOut));
int toadd_count=0;//state->get_contact_count();
RigidBody2D_RemoveAction *toremove=(RigidBody2D_RemoveAction*)alloca(rc*sizeof(RigidBody2D_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_block_transform_notify(true); // don't want notify (would feedback loop)
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_block_transform_notify(false); // want it back
state=NULL;
}
void RigidBody2D::_notification(int p_what) {
}
void RigidBody2D::set_mode(Mode p_mode) {
mode=p_mode;
switch(p_mode) {
case MODE_RIGID: {
Physics2DServer::get_singleton()->body_set_mode(get_rid(),Physics2DServer::BODY_MODE_RIGID);
} break;
case MODE_STATIC: {
Physics2DServer::get_singleton()->body_set_mode(get_rid(),Physics2DServer::BODY_MODE_STATIC);
} break;
case MODE_STATIC_ACTIVE: {
Physics2DServer::get_singleton()->body_set_mode(get_rid(),Physics2DServer::BODY_MODE_STATIC_ACTIVE);
} break;
case MODE_CHARACTER: {
Physics2DServer::get_singleton()->body_set_mode(get_rid(),Physics2DServer::BODY_MODE_CHARACTER);
} break;
}
}
RigidBody2D::Mode RigidBody2D::get_mode() const{
return mode;
}
void RigidBody2D::set_mass(real_t p_mass){
ERR_FAIL_COND(p_mass<=0);
mass=p_mass;
_change_notify("mass");
_change_notify("weight");
Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_MASS,mass);
}
real_t RigidBody2D::get_mass() const{
return mass;
}
void RigidBody2D::set_weight(real_t p_weight){
set_mass(p_weight/9.8);
}
real_t RigidBody2D::get_weight() const{
return mass*9.8;
}
void RigidBody2D::set_friction(real_t p_friction){
ERR_FAIL_COND(p_friction<0 || p_friction>1);
friction=p_friction;
Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_FRICTION,friction);
}
real_t RigidBody2D::get_friction() const{
return friction;
}
void RigidBody2D::set_bounce(real_t p_bounce){
ERR_FAIL_COND(p_bounce<0 || p_bounce>1);
bounce=p_bounce;
Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_BOUNCE,bounce);
}
real_t RigidBody2D::get_bounce() const{
return bounce;
}
void RigidBody2D::set_axis_velocity(const Vector2& p_axis) {
Vector2 v = state? state->get_linear_velocity() : linear_velocity;
Vector2 axis = p_axis.normalized();
v-=axis*axis.dot(v);
v+=p_axis;
if (state) {
set_linear_velocity(v);
} else {
Physics2DServer::get_singleton()->body_set_axis_velocity(get_rid(),p_axis);
linear_velocity=v;
}
}
void RigidBody2D::set_linear_velocity(const Vector2& p_velocity){
linear_velocity=p_velocity;
if (state)
state->set_linear_velocity(linear_velocity);
else {
Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_LINEAR_VELOCITY,linear_velocity);
}
}
Vector2 RigidBody2D::get_linear_velocity() const{
return linear_velocity;
}
void RigidBody2D::set_angular_velocity(real_t p_velocity){
angular_velocity=p_velocity;
if (state)
state->set_angular_velocity(angular_velocity);
else
Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_ANGULAR_VELOCITY,angular_velocity);
}
real_t RigidBody2D::get_angular_velocity() const{
return angular_velocity;
}
void RigidBody2D::set_use_custom_integrator(bool p_enable){
if (custom_integrator==p_enable)
return;
custom_integrator=p_enable;
Physics2DServer::get_singleton()->body_set_omit_force_integration(get_rid(),p_enable);
}
bool RigidBody2D::is_using_custom_integrator(){
return custom_integrator;
}
void RigidBody2D::set_active(bool p_active) {
active=p_active;
Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_SLEEPING,!active);
}
void RigidBody2D::set_can_sleep(bool p_active) {
can_sleep=p_active;
Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_CAN_SLEEP,p_active);
}
bool RigidBody2D::is_able_to_sleep() const {
return can_sleep;
}
bool RigidBody2D::is_active() const {
return active;
}
void RigidBody2D::set_max_contacts_reported(int p_amount) {
max_contacts_reported=p_amount;
Physics2DServer::get_singleton()->body_set_max_contacts_reported(get_rid(),p_amount);
}
int RigidBody2D::get_max_contacts_reported() const{
return max_contacts_reported;
}
void RigidBody2D::apply_impulse(const Vector2& p_pos, const Vector2& p_impulse) {
Physics2DServer::get_singleton()->body_apply_impulse(get_rid(),p_pos,p_impulse);
}
void RigidBody2D::set_applied_force(const Vector2& p_force) {
Physics2DServer::get_singleton()->body_set_applied_force(get_rid(), p_force);
};
Vector2 RigidBody2D::get_applied_force() const {
return Physics2DServer::get_singleton()->body_get_applied_force(get_rid());
};
void RigidBody2D::set_use_continuous_collision_detection(bool p_enable) {
ccd=p_enable;
Physics2DServer::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(),p_enable);
}
bool RigidBody2D::is_using_continuous_collision_detection() const {
return ccd;
}
void RigidBody2D::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 RigidBody2D::is_contact_monitor_enabled() const {
return contact_monitor!=NULL;
}
void RigidBody2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_mode","mode"),&RigidBody2D::set_mode);
ObjectTypeDB::bind_method(_MD("get_mode"),&RigidBody2D::get_mode);
ObjectTypeDB::bind_method(_MD("set_mass","mass"),&RigidBody2D::set_mass);
ObjectTypeDB::bind_method(_MD("get_mass"),&RigidBody2D::get_mass);
ObjectTypeDB::bind_method(_MD("set_weight","weight"),&RigidBody2D::set_weight);
ObjectTypeDB::bind_method(_MD("get_weight"),&RigidBody2D::get_weight);
ObjectTypeDB::bind_method(_MD("set_friction","friction"),&RigidBody2D::set_friction);
ObjectTypeDB::bind_method(_MD("get_friction"),&RigidBody2D::get_friction);
ObjectTypeDB::bind_method(_MD("set_bounce","bounce"),&RigidBody2D::set_bounce);
ObjectTypeDB::bind_method(_MD("get_bounce"),&RigidBody2D::get_bounce);
ObjectTypeDB::bind_method(_MD("set_linear_velocity","linear_velocity"),&RigidBody2D::set_linear_velocity);
ObjectTypeDB::bind_method(_MD("get_linear_velocity"),&RigidBody2D::get_linear_velocity);
ObjectTypeDB::bind_method(_MD("set_angular_velocity","angular_velocity"),&RigidBody2D::set_angular_velocity);
ObjectTypeDB::bind_method(_MD("get_angular_velocity"),&RigidBody2D::get_angular_velocity);
ObjectTypeDB::bind_method(_MD("set_max_contacts_reported","amount"),&RigidBody2D::set_max_contacts_reported);
ObjectTypeDB::bind_method(_MD("get_max_contacts_reported"),&RigidBody2D::get_max_contacts_reported);
ObjectTypeDB::bind_method(_MD("set_use_custom_integrator","enable"),&RigidBody2D::set_use_custom_integrator);
ObjectTypeDB::bind_method(_MD("is_using_custom_integrator"),&RigidBody2D::is_using_custom_integrator);
ObjectTypeDB::bind_method(_MD("set_contact_monitor","enabled"),&RigidBody2D::set_contact_monitor);
ObjectTypeDB::bind_method(_MD("is_contact_monitor_enabled"),&RigidBody2D::is_contact_monitor_enabled);
ObjectTypeDB::bind_method(_MD("set_use_continuous_collision_detection","enable"),&RigidBody2D::set_use_continuous_collision_detection);
ObjectTypeDB::bind_method(_MD("is_using_continuous_collision_detection"),&RigidBody2D::is_using_continuous_collision_detection);
ObjectTypeDB::bind_method(_MD("set_axis_velocity","axis_velocity"),&RigidBody2D::set_axis_velocity);
ObjectTypeDB::bind_method(_MD("apply_impulse","pos","impulse"),&RigidBody2D::apply_impulse);
ObjectTypeDB::bind_method(_MD("set_applied_force","force"),&RigidBody2D::set_applied_force);
ObjectTypeDB::bind_method(_MD("get_applied_force"),&RigidBody2D::get_applied_force);
ObjectTypeDB::bind_method(_MD("set_active","active"),&RigidBody2D::set_active);
ObjectTypeDB::bind_method(_MD("is_active"),&RigidBody2D::is_active);
ObjectTypeDB::bind_method(_MD("set_can_sleep","able_to_sleep"),&RigidBody2D::set_can_sleep);
ObjectTypeDB::bind_method(_MD("is_able_to_sleep"),&RigidBody2D::is_able_to_sleep);
ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&RigidBody2D::_direct_state_changed);
ObjectTypeDB::bind_method(_MD("_body_enter_scene"),&RigidBody2D::_body_enter_scene);
ObjectTypeDB::bind_method(_MD("_body_exit_scene"),&RigidBody2D::_body_exit_scene);
BIND_VMETHOD(MethodInfo("_integrate_forces",PropertyInfo(Variant::OBJECT,"state:Physics2DDirectBodyState")));
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::VECTOR2,"velocity/linear"),_SCS("set_linear_velocity"),_SCS("get_linear_velocity"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"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 );
}
RigidBody2D::RigidBody2D() : PhysicsBody2D(Physics2DServer::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;
Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_direct_state_changed");
}
RigidBody2D::~RigidBody2D() {
if (contact_monitor)
memdelete( contact_monitor );
}

232
scene/2d/physics_body_2d.h Normal file
View File

@ -0,0 +1,232 @@
/*************************************************************************/
/* physics_body_2d.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_2D_H
#define PHYSICS_BODY_2D_H
#include "scene/2d/collision_object_2d.h"
#include "servers/physics_2d_server.h"
#include "vset.h"
class PhysicsBody2D : public CollisionObject2D {
OBJ_TYPE(PhysicsBody2D,CollisionObject2D);
protected:
void _notification(int p_what);
PhysicsBody2D(Physics2DServer::BodyMode p_mode);
public:
PhysicsBody2D();
};
class StaticBody2D : public PhysicsBody2D {
OBJ_TYPE(StaticBody2D,PhysicsBody2D);
Matrix32 *pre_xform;
//RID query;
bool setting;
bool pending;
bool simulating_motion;
Vector2 constant_linear_velocity;
real_t constant_angular_velocity;
void _update_xform();
void _state_notify(Object *p_object);
real_t bounce;
real_t friction;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
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_simulate_motion(bool p_enable);
bool is_simulating_motion() const;
void set_constant_linear_velocity(const Vector2& p_vel);
void set_constant_angular_velocity(real_t p_vel);
Vector2 get_constant_linear_velocity() const;
real_t get_constant_angular_velocity() const;
StaticBody2D();
~StaticBody2D();
};
class RigidBody2D : public PhysicsBody2D {
OBJ_TYPE(RigidBody2D,PhysicsBody2D);
public:
enum Mode {
MODE_RIGID,
MODE_STATIC,
MODE_CHARACTER,
MODE_STATIC_ACTIVE,
};
private:
bool can_sleep;
Physics2DDirectBodyState *state;
Mode mode;
real_t bounce;
real_t mass;
real_t friction;
Vector2 linear_velocity;
real_t 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 RigidBody2D_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 Vector2& p_velocity);
Vector2 get_linear_velocity() const;
void set_axis_velocity(const Vector2& p_axis);
void set_angular_velocity(real_t p_velocity);
real_t 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 Vector2& p_pos, const Vector2& p_impulse);
void set_applied_force(const Vector2& p_force);
Vector2 get_applied_force() const;
RigidBody2D();
~RigidBody2D();
};
VARIANT_ENUM_CAST(RigidBody2D::Mode);
#endif // PHYSICS_BODY_2D_H

65
scene/2d/position_2d.cpp Normal file
View File

@ -0,0 +1,65 @@
/*************************************************************************/
/* position_2d.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_2d.h"
#include "scene/resources/texture.h"
void Position2D::_draw_cross() {
draw_line(Point2(-10,0),Point2(+10,0),Color(1,0.5,0.5));
draw_line(Point2(0,-10),Point2(0,+10),Color(0.5,1,0.5));
}
Rect2 Position2D::get_item_rect() const {
return Rect2(Point2(-10,-10),Size2(20,20));
}
void Position2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_SCENE: {
update();
} break;
case NOTIFICATION_DRAW: {
if (!is_inside_scene())
break;
if (get_scene()->is_editor_hint())
_draw_cross();
} break;
}
}
Position2D::Position2D()
{
}

49
scene/2d/position_2d.h Normal file
View File

@ -0,0 +1,49 @@
/*************************************************************************/
/* position_2d.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_2D_H
#define POSITION_2D_H
#include "scene/2d/node_2d.h"
class Position2D : public Node2D {
OBJ_TYPE(Position2D,Node2D)
void _draw_cross();
protected:
void _notification(int p_what);
public:
virtual Rect2 get_item_rect() const;
Position2D();
};
#endif // POSITION_2D_H

198
scene/2d/ray_cast_2d.cpp Normal file
View File

@ -0,0 +1,198 @@
/*************************************************************************/
/* ray_cast_2d.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_2d.h"
#include "servers/physics_2d_server.h"
void RayCast2D::set_cast_to(const Vector2& p_point) {
cast_to=p_point;
if (is_inside_scene() && get_scene()->is_editor_hint())
update();
}
Vector2 RayCast2D::get_cast_to() const{
return cast_to;
}
bool RayCast2D::is_colliding() const{
return collided;
}
Object *RayCast2D::get_collider() const{
if (against==0)
return NULL;
return ObjectDB::get_instance(against);
}
int RayCast2D::get_collider_shape() const {
return against_shape;
}
Vector2 RayCast2D::get_collision_point() const{
return collision_point;
}
Vector2 RayCast2D::get_collision_normal() const{
return collision_normal;
}
void RayCast2D::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 RayCast2D::is_enabled() const {
return enabled;
}
void RayCast2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_SCENE: {
if (enabled && !get_scene()->is_editor_hint())
set_fixed_process(true);
else
set_fixed_process(false);
} break;
case NOTIFICATION_EXIT_SCENE: {
if (enabled)
set_fixed_process(false);
} break;
#ifdef TOOLS_ENABLED
case NOTIFICATION_DRAW: {
if (!get_scene()->is_editor_hint())
break;
Matrix32 xf;
xf.rotate(cast_to.atan2());
xf.translate(Vector2(0,cast_to.length()));
//Vector2 tip = Vector2(0,s->get_length());
Color dcol(0.9,0.2,0.2,0.4);
draw_line(Vector2(),cast_to,dcol,3);
Vector<Vector2> pts;
float tsize=4;
pts.push_back(xf.xform(Vector2(0,tsize)));
pts.push_back(xf.xform(Vector2(0.707*tsize,0)));
pts.push_back(xf.xform(Vector2(-0.707*tsize,0)));
Vector<Color> cols;
for(int i=0;i<3;i++)
cols.push_back(dcol);
draw_primitive(pts,cols,Vector<Vector2>()); //small arrow
} break;
#endif
case NOTIFICATION_FIXED_PROCESS: {
if (!enabled)
break;
Ref<World2D> w2d = get_world_2d();
ERR_BREAK( w2d.is_null() );
Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(w2d->get_space());
ERR_BREAK( !dss );
Matrix32 gt = get_global_transform();
Vector2 to = cast_to;
if (to==Vector2())
to=Vector2(0,0.01);
Physics2DDirectSpaceState::RayResult rr;
if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr)) {
collided=true;
against=rr.collider_id;
collision_point=rr.position;
collision_normal=rr.normal;
against_shape=rr.shape;
} else {
collided=false;
}
} break;
}
}
void RayCast2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&RayCast2D::set_enabled);
ObjectTypeDB::bind_method(_MD("is_enabled"),&RayCast2D::is_enabled);
ObjectTypeDB::bind_method(_MD("set_cast_to","local_point"),&RayCast2D::set_cast_to);
ObjectTypeDB::bind_method(_MD("get_cast_to"),&RayCast2D::get_cast_to);
ObjectTypeDB::bind_method(_MD("is_colliding"),&RayCast2D::is_colliding);
ObjectTypeDB::bind_method(_MD("get_collider"),&RayCast2D::get_collider);
ObjectTypeDB::bind_method(_MD("get_collider_shape"),&RayCast2D::get_collider_shape);
ObjectTypeDB::bind_method(_MD("get_collision_point"),&RayCast2D::get_collision_point);
ObjectTypeDB::bind_method(_MD("get_collision_normal"),&RayCast2D::get_collision_normal);
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to"));
}
RayCast2D::RayCast2D() {
enabled=false;
against=0;
collided=false;
against_shape=0;
cast_to=Vector2(0,50);
}

68
scene/2d/ray_cast_2d.h Normal file
View File

@ -0,0 +1,68 @@
/*************************************************************************/
/* ray_cast_2d.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_2D_H
#define RAY_CAST_2D_H
#include "scene/2d/node_2d.h"
class RayCast2D : public Node2D {
OBJ_TYPE(RayCast2D,Node2D);
bool enabled;
bool collided;
ObjectID against;
int against_shape;
Vector2 collision_point;
Vector2 collision_normal;
Vector2 cast_to;
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 Vector2& p_point);
Vector2 get_cast_to() const;
bool is_colliding() const;
Object *get_collider() const;
int get_collider_shape() const;
Vector2 get_collision_point() const;
Vector2 get_collision_normal() const;
RayCast2D();
};
#endif // RAY_CAST_2D_H

View File

@ -0,0 +1,122 @@
/*************************************************************************/
/* remote_transform_2d.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 "remote_transform_2d.h"
#include "scene/scene_string_names.h"
void RemoteTransform2D::_update_cache() {
cache=0;
if (has_node(remote_node)) {
Node *node = get_node(remote_node);
if (!node || this==node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) {
return;
}
cache=node->get_instance_ID();
}
}
void RemoteTransform2D::_update_remote() {
if (!is_inside_scene())
return;
if (!cache)
return;
Object *obj = ObjectDB::get_instance(cache);
if (!obj)
return;
Node2D *n = obj->cast_to<Node2D>();
if (!n)
return;
if (!n->is_inside_scene())
return;
//todo make faster
n->set_global_transform(get_global_transform());
}
void RemoteTransform2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_READY: {
_update_cache();
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
if (!is_inside_scene())
break;
if (cache) {
_update_remote();
}
} break;
}
}
void RemoteTransform2D::set_remote_node(const NodePath& p_remote_node) {
remote_node=p_remote_node;
if (is_inside_scene())
_update_cache();
}
NodePath RemoteTransform2D::get_remote_node() const{
return remote_node;
}
void RemoteTransform2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_remote_node","path"),&RemoteTransform2D::set_remote_node);
ObjectTypeDB::bind_method(_MD("get_remote_node"),&RemoteTransform2D::get_remote_node);
ADD_PROPERTY( PropertyInfo(Variant::NODE_PATH,"remote_path"),_SCS("set_remote_node"),_SCS("get_remote_node"));
}
RemoteTransform2D::RemoteTransform2D() {
cache=0;
}

View File

@ -0,0 +1,52 @@
/*************************************************************************/
/* remote_transform_2d.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. */
/*************************************************************************/
#include "scene/2d/node_2d.h"
class RemoteTransform2D : public Node2D {
OBJ_TYPE(RemoteTransform2D,Node2D);
NodePath remote_node;
ObjectID cache;
void _update_remote();
void _update_cache();
void _node_exited_scene();
protected:
static void _bind_methods();
void _notification(int p_what);
public:
void set_remote_node(const NodePath& p_remote_node);
NodePath get_remote_node() const;
RemoteTransform2D();
};

View File

@ -0,0 +1,252 @@
/*************************************************************************/
/* sample_player_2d.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 "sample_player_2d.h"
#include "servers/audio_server.h"
#include "servers/audio_server.h"
#include "servers/spatial_sound_server.h"
bool SamplePlayer2D::_set(const StringName& p_name, const Variant& p_value) {
String name=p_name;
if (name=="play/play") {
if (library.is_valid()) {
String what=p_value;
if (what=="")
stop_all();
else
play(what);
played_back=what;
}
} else
return false;
return true;
}
bool SamplePlayer2D::_get(const StringName& p_name,Variant &r_ret) const {
String name=p_name;
if (name=="play/play") {
r_ret=played_back;
} else
return false;
return true;
}
void SamplePlayer2D::_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 SamplePlayer2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_SCENE: {
SpatialSound2DServer::get_singleton()->source_set_polyphony(get_source_rid(),polyphony);
} break;
}
}
void SamplePlayer2D::set_sample_library(const Ref<SampleLibrary>& p_library) {
library=p_library;
}
Ref<SampleLibrary> SamplePlayer2D::get_sample_library() const {
return library;
}
void SamplePlayer2D::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())
SpatialSound2DServer::get_singleton()->source_set_polyphony(get_source_rid(),polyphony);
}
int SamplePlayer2D::get_polyphony() const {
return polyphony;
}
SamplePlayer2D::VoiceID SamplePlayer2D::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 = SpatialSound2DServer::get_singleton()->source_play_sample(get_source_rid(),sample->get_rid(),sample->get_mix_rate()*pitch_change,p_voice);
if (vol_change)
SpatialSound2DServer::get_singleton()->source_voice_set_volume_scale_db(get_source_rid(),vid,vol_change);
if (random_pitch_scale) {
float ps = Math::random(-random_pitch_scale,random_pitch_scale);
if (ps>0)
ps=1.0+ps;
else
ps=1.0/(1.0-ps);
SpatialSound2DServer::get_singleton()->source_voice_set_pitch_scale(get_source_rid(),vid,ps*pitch_change);
}
return vid;
}
//voices
void SamplePlayer2D::voice_set_pitch_scale(VoiceID p_voice, float p_pitch_scale) {
if (!get_source_rid().is_valid())
return;
SpatialSound2DServer::get_singleton()->source_voice_set_pitch_scale(get_source_rid(),p_voice,p_pitch_scale);
}
void SamplePlayer2D::voice_set_volume_scale_db(VoiceID p_voice, float p_volume_db) {
if (!get_source_rid().is_valid())
return;
SpatialSound2DServer::get_singleton()->source_voice_set_volume_scale_db(get_source_rid(),p_voice,p_volume_db);
}
bool SamplePlayer2D::is_voice_active(VoiceID p_voice) const {
if (!get_source_rid().is_valid())
return false;
return SpatialSound2DServer::get_singleton()->source_is_voice_active(get_source_rid(),p_voice);
}
void SamplePlayer2D::stop_voice(VoiceID p_voice) {
if (!get_source_rid().is_valid())
return;
SpatialSound2DServer::get_singleton()->source_stop_voice(get_source_rid(),p_voice);
}
void SamplePlayer2D::stop_all() {
if (!get_source_rid().is_valid())
return;
for(int i=0;i<polyphony;i++) {
SpatialSound2DServer::get_singleton()->source_stop_voice(get_source_rid(),i);
}
}
void SamplePlayer2D::set_random_pitch_scale(float p_scale) {
random_pitch_scale=p_scale;
}
float SamplePlayer2D::get_random_pitch_scale() const {
return random_pitch_scale;
}
void SamplePlayer2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_sample_library","library:SampleLibrary"),&SamplePlayer2D::set_sample_library);
ObjectTypeDB::bind_method(_MD("get_sample_library:SampleLibrary"),&SamplePlayer2D::get_sample_library);
ObjectTypeDB::bind_method(_MD("set_polyphony","voices"),&SamplePlayer2D::set_polyphony);
ObjectTypeDB::bind_method(_MD("get_polyphony"),&SamplePlayer2D::get_polyphony);
ObjectTypeDB::bind_method(_MD("play","sample","voice"),&SamplePlayer2D::play,DEFVAL(NEXT_VOICE));
//voices,DEV
ObjectTypeDB::bind_method(_MD("voice_set_pitch_scale","voice","ratio"),&SamplePlayer2D::voice_set_pitch_scale);
ObjectTypeDB::bind_method(_MD("voice_set_volume_scale_db","voice","db"),&SamplePlayer2D::voice_set_volume_scale_db);
ObjectTypeDB::bind_method(_MD("is_voice_active","voice"),&SamplePlayer2D::is_voice_active);
ObjectTypeDB::bind_method(_MD("stop_voice","voice"),&SamplePlayer2D::stop_voice);
ObjectTypeDB::bind_method(_MD("stop_all"),&SamplePlayer2D::stop_all);
ObjectTypeDB::bind_method(_MD("set_random_pitch_scale","val"),&SamplePlayer2D::set_random_pitch_scale);
ObjectTypeDB::bind_method(_MD("get_random_pitch_scale"),&SamplePlayer2D::get_random_pitch_scale);
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"));
ADD_PROPERTY( PropertyInfo( Variant::REAL, "config/pitch_random", PROPERTY_HINT_RESOURCE_TYPE,"SampleLibrary"),_SCS("set_random_pitch_scale"),_SCS("get_random_pitch_scale"));
}
SamplePlayer2D::SamplePlayer2D() {
polyphony=1;
random_pitch_scale=0;
}
SamplePlayer2D::~SamplePlayer2D() {
}

View File

@ -0,0 +1,92 @@
/*************************************************************************/
/* sample_player_2d.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 SAMPLE_PLAYER_2D_H
#define SAMPLE_PLAYER_2D_H
#include "scene/2d/sound_player_2d.h"
#include "scene/resources/sample_library.h"
class SamplePlayer2D : public SoundPlayer2D {
OBJ_TYPE(SamplePlayer2D,SoundPlayer2D);
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;
float random_pitch_scale;
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();
void set_random_pitch_scale(float p_scale);
float get_random_pitch_scale() const;
SamplePlayer2D();
~SamplePlayer2D();
};
#endif // SAMPLE_PLAYER_2D_H

372
scene/2d/screen_button.cpp Normal file
View File

@ -0,0 +1,372 @@
/*************************************************************************/
/* screen_button.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 "screen_button.h"
#include "os/os.h"
#include "input_map.h"
#include "os/input.h"
void TouchScreenButton::set_texture(const Ref<Texture>& p_texture) {
texture=p_texture;
update();
}
Ref<Texture> TouchScreenButton::get_texture() const{
return texture;
}
void TouchScreenButton::set_texture_pressed(const Ref<Texture>& p_texture_pressed) {
texture_pressed=p_texture_pressed;
update();
}
Ref<Texture> TouchScreenButton::get_texture_pressed() const{
return texture_pressed;
}
void TouchScreenButton::set_bitmask(const Ref<BitMap>& p_bitmask){
bitmask=p_bitmask;
}
Ref<BitMap> TouchScreenButton::get_bitmask() const{
return bitmask;
}
void TouchScreenButton::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
if (!is_inside_scene())
return;
if (!get_scene()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY)
return;
if (finger_pressed!=-1) {
if (texture_pressed.is_valid())
draw_texture(texture_pressed,Point2());
else if (texture.is_valid())
draw_texture(texture,Point2());
} else {
if (texture.is_valid())
draw_texture(texture,Point2());
}
} break;
case NOTIFICATION_ENTER_SCENE: {
if (!get_scene()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY)
return;
update();
set_process_input(true);
if (action.operator String()!="" && InputMap::get_singleton()->has_action(action)) {
action_id=InputMap::get_singleton()->get_action_id(action);
} else {
action_id=-1;
}
} break;
}
}
bool TouchScreenButton::is_pressed() const{
return finger_pressed!=-1;
}
void TouchScreenButton::set_action(const String& p_action) {
action=p_action;
if (action.operator String()!="" && InputMap::get_singleton()->has_action(action)) {
action_id=InputMap::get_singleton()->get_action_id(action);
} else {
action_id=-1;
}
}
String TouchScreenButton::get_action() const {
return action;
}
void TouchScreenButton::_input(const InputEvent& p_event) {
if (!get_scene())
return;
if (passby_press) {
if (p_event.type==InputEvent::SCREEN_TOUCH && !p_event.screen_touch.pressed && finger_pressed==p_event.screen_touch.index) {
emit_signal("released");
if (action_id!=-1) {
Input::get_singleton()->action_release(action);
InputEvent ie;
ie.type=InputEvent::ACTION;
ie.ID=0;
ie.action.action=action_id;
ie.action.pressed=false;
get_scene()->input_event(ie);
}
finger_pressed=-1;
update();
}
if ((p_event.type==InputEvent::SCREEN_TOUCH && p_event.screen_touch.pressed)|| p_event.type==InputEvent::SCREEN_DRAG) {
if (finger_pressed==-1 || p_event.screen_touch.index==finger_pressed) {
Point2 coord = (get_viewport_transform() * get_global_transform()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y));
bool touched=false;
if (bitmask.is_valid()) {
if (Rect2(Point2(),bitmask->get_size()).has_point(coord)) {
if (bitmask->get_bit(coord))
touched=true;
}
} else {
touched=Rect2(Point2(),texture->get_size()).has_point(coord);
}
if (touched) {
if (finger_pressed==-1) {
finger_pressed=p_event.screen_touch.index;
//emit change stuff
emit_signal("pressed");
if (action_id!=-1) {
Input::get_singleton()->action_press(action);
InputEvent ie;
ie.type=InputEvent::ACTION;
ie.ID=0;
ie.action.action=action_id;
ie.action.pressed=true;
get_scene()->input_event(ie);
}
update();
}
} else {
if (finger_pressed!=-1) {
emit_signal("released");
if (action_id!=-1) {
Input::get_singleton()->action_release(action);
InputEvent ie;
ie.type=InputEvent::ACTION;
ie.ID=0;
ie.action.action=action_id;
ie.action.pressed=false;
get_scene()->input_event(ie);
}
finger_pressed=-1;
update();
}
}
}
}
} else {
if (p_event.type==InputEvent::SCREEN_TOUCH) {
if (p_event.screen_touch.pressed) {
if (!is_visible())
return;
if (finger_pressed!=-1)
return; //already fingering
Point2 coord = (get_viewport_transform() * get_global_transform()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y));
bool touched=false;
if (bitmask.is_valid()) {
if (Rect2(Point2(),bitmask->get_size()).has_point(coord)) {
if (bitmask->get_bit(coord))
touched=true;
}
} else {
touched=Rect2(Point2(),texture->get_size()).has_point(coord);
}
if (touched) {
finger_pressed=p_event.screen_touch.index;
//emit change stuff
emit_signal("pressed");
if (action_id!=-1) {
Input::get_singleton()->action_press(action);
InputEvent ie;
ie.type=InputEvent::ACTION;
ie.ID=0;
ie.action.action=action_id;
ie.action.pressed=true;
get_scene()->input_event(ie);
}
update();
}
} else {
if (p_event.screen_touch.index==finger_pressed) {
//untouch
emit_signal("released");
if (action_id!=-1) {
Input::get_singleton()->action_release(action);
InputEvent ie;
ie.type=InputEvent::ACTION;
ie.ID=0;
ie.action.action=action_id;
ie.action.pressed=false;
get_scene()->input_event(ie);
}
finger_pressed=-1;
update();
}
}
}
}
}
Rect2 TouchScreenButton::get_item_rect() const {
if (texture.is_null())
return Rect2(0,0,1,1);
//if (texture.is_null())
// return CanvasItem::get_item_rect();
return Rect2(Size2(),texture->get_size());
}
void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) {
visibility=p_mode;
update();
}
TouchScreenButton::VisibilityMode TouchScreenButton::get_visibility_mode() const {
return visibility;
}
void TouchScreenButton::set_passby_press(bool p_enable) {
passby_press=p_enable;
}
bool TouchScreenButton::is_passby_press_enabled() const{
return passby_press;
}
void TouchScreenButton::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_texture","texture"),&TouchScreenButton::set_texture);
ObjectTypeDB::bind_method(_MD("get_texture"),&TouchScreenButton::get_texture);
ObjectTypeDB::bind_method(_MD("set_texture_pressed","texture_pressed"),&TouchScreenButton::set_texture_pressed);
ObjectTypeDB::bind_method(_MD("get_texture_pressed"),&TouchScreenButton::get_texture_pressed);
ObjectTypeDB::bind_method(_MD("set_bitmask","bitmask"),&TouchScreenButton::set_bitmask);
ObjectTypeDB::bind_method(_MD("get_bitmask"),&TouchScreenButton::get_bitmask);
ObjectTypeDB::bind_method(_MD("set_action","action"),&TouchScreenButton::set_action);
ObjectTypeDB::bind_method(_MD("get_action"),&TouchScreenButton::get_action);
ObjectTypeDB::bind_method(_MD("set_visibility_mode","mode"),&TouchScreenButton::set_visibility_mode);
ObjectTypeDB::bind_method(_MD("get_visibility_mode"),&TouchScreenButton::get_visibility_mode);
ObjectTypeDB::bind_method(_MD("set_passby_press","enabled"),&TouchScreenButton::set_passby_press);
ObjectTypeDB::bind_method(_MD("is_passby_press_enabled"),&TouchScreenButton::is_passby_press_enabled);
ObjectTypeDB::bind_method(_MD("is_pressed"),&TouchScreenButton::is_pressed);
ObjectTypeDB::bind_method(_MD("_input"),&TouchScreenButton::_input);
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"normal",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"pressed",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture_pressed"),_SCS("get_texture_pressed"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"bitmask",PROPERTY_HINT_RESOURCE_TYPE,"BitMap"),_SCS("set_bitmask"),_SCS("get_bitmask"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"passby_press"),_SCS("set_passby_press"),_SCS("is_passby_press_enabled"));
ADD_PROPERTY( PropertyInfo(Variant::STRING,"action"),_SCS("set_action"),_SCS("get_action"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"visibility_mode",PROPERTY_HINT_ENUM,"Always,TouchScreen Only"),_SCS("set_visibility_mode"),_SCS("get_visibility_mode"));
ADD_SIGNAL( MethodInfo("pressed" ) );
ADD_SIGNAL( MethodInfo("release" ) );
}
TouchScreenButton::TouchScreenButton() {
finger_pressed=-1;
action_id=-1;
passby_press=false;
visibility=VISIBILITY_ALWAYS;
}

95
scene/2d/screen_button.h Normal file
View File

@ -0,0 +1,95 @@
/*************************************************************************/
/* screen_button.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 SCREEN_BUTTON_H
#define SCREEN_BUTTON_H
#include "scene/2d/node_2d.h"
#include "scene/resources/texture.h"
#include "scene/resources/bit_mask.h"
class TouchScreenButton : public Node2D {
OBJ_TYPE(TouchScreenButton,Node2D);
public:
enum VisibilityMode {
VISIBILITY_ALWAYS,
VISIBILITY_TOUCHSCREEN_ONLY
};
private:
Ref<Texture> texture;
Ref<Texture> texture_pressed;
Ref<BitMap> bitmask;
StringName action;
bool passby_press;
int finger_pressed;
int action_id;
VisibilityMode visibility;
void _input(const InputEvent& p_Event);
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void set_texture(const Ref<Texture>& p_texture);
Ref<Texture> get_texture() const;
void set_texture_pressed(const Ref<Texture>& p_texture_pressed);
Ref<Texture> get_texture_pressed() const;
void set_bitmask(const Ref<BitMap>& p_bitmask);
Ref<BitMap> get_bitmask() const;
void set_action(const String& p_action);
String get_action() const;
void set_passby_press(bool p_enable);
bool is_passby_press_enabled() const;
void set_visibility_mode(VisibilityMode p_mode);
VisibilityMode get_visibility_mode() const;
bool is_pressed() const;
Rect2 get_item_rect() const;
TouchScreenButton();
};
VARIANT_ENUM_CAST(TouchScreenButton::VisibilityMode);
#endif // SCREEN_BUTTON_H

View File

@ -0,0 +1,123 @@
/*************************************************************************/
/* sound_player_2d.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 "sound_player_2d.h"
#include "servers/audio_server.h"
#include "servers/spatial_sound_2d_server.h"
#include "scene/resources/surface_tool.h"
void SoundPlayer2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_SCENE: {
//find the sound space
source_rid = SpatialSound2DServer::get_singleton()->source_create(get_world_2d()->get_sound_space());
for(int i=0;i<PARAM_MAX;i++)
set_param(Param(i),params[i]);
SpatialSound2DServer::get_singleton()->source_set_transform(source_rid,get_global_transform());
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
SpatialSound2DServer::get_singleton()->source_set_transform(source_rid,get_global_transform());
} break;
case NOTIFICATION_EXIT_SCENE: {
if (source_rid.is_valid())
SpatialSound2DServer::get_singleton()->free(source_rid);
} break;
}
}
void SoundPlayer2D::set_param( Param p_param, float p_value) {
ERR_FAIL_INDEX(p_param,PARAM_MAX);
params[p_param]=p_value;
if (source_rid.is_valid())
SpatialSound2DServer::get_singleton()->source_set_param(source_rid,(SpatialSound2DServer::SourceParam)p_param,p_value);
}
float SoundPlayer2D::get_param( Param p_param) const {
ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
return params[p_param];
}
void SoundPlayer2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_param","param","value"),&SoundPlayer2D::set_param);
ObjectTypeDB::bind_method(_MD("get_param","param"),&SoundPlayer2D::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_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_EXP_RANGE, "16,16384,1"),_SCS("set_param"),_SCS("get_param"),PARAM_ATTENUATION_MIN_DISTANCE);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation/max_distance",PROPERTY_HINT_EXP_RANGE, "16,16384,1"),_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);
}
SoundPlayer2D::SoundPlayer2D() {
params[PARAM_VOLUME_DB]=0.0;
params[PARAM_PITCH_SCALE]=1.0;
params[PARAM_ATTENUATION_MIN_DISTANCE]=1;
params[PARAM_ATTENUATION_MAX_DISTANCE]=2048;
params[PARAM_ATTENUATION_DISTANCE_EXP]=1.0; //linear (and not really good)
}
SoundPlayer2D::~SoundPlayer2D() {
}

View File

@ -0,0 +1,82 @@
/*************************************************************************/
/* sound_player_2d.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 SOUND_PLAYER_2D_H
#define SOUND_PLAYER_2D_H
#include "scene/2d/node_2d.h"
#include "scene/resources/sample_library.h"
#include "servers/spatial_sound_2d_server.h"
#include "scene/main/viewport.h"
class SoundPlayer2D : public Node2D {
OBJ_TYPE(SoundPlayer2D,Node2D);
public:
enum Param {
PARAM_VOLUME_DB=SpatialSound2DServer::SOURCE_PARAM_VOLUME_DB,
PARAM_PITCH_SCALE=SpatialSound2DServer::SOURCE_PARAM_PITCH_SCALE,
PARAM_ATTENUATION_MIN_DISTANCE=SpatialSound2DServer::SOURCE_PARAM_ATTENUATION_MIN_DISTANCE,
PARAM_ATTENUATION_MAX_DISTANCE=SpatialSound2DServer::SOURCE_PARAM_ATTENUATION_MAX_DISTANCE,
PARAM_ATTENUATION_DISTANCE_EXP=SpatialSound2DServer::SOURCE_PARAM_ATTENUATION_DISTANCE_EXP,
PARAM_MAX=SpatialSound2DServer::SOURCE_PARAM_MAX
};
private:
float params[PARAM_MAX];
RID source_rid;
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;
SoundPlayer2D();
~SoundPlayer2D();
};
VARIANT_ENUM_CAST(SoundPlayer2D::Param );
#endif // SOUND_PLAYER_2D_H

337
scene/2d/sprite.cpp Normal file
View File

@ -0,0 +1,337 @@
/*************************************************************************/
/* sprite.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 "sprite.h"
#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
void Sprite::edit_set_pivot(const Point2& p_pivot) {
set_offset(p_pivot);
}
Point2 Sprite::edit_get_pivot() const {
return get_offset();
}
bool Sprite::edit_has_pivot() const {
return true;
}
void Sprite::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
if (texture.is_null())
return;
RID ci = get_canvas_item();
/*
texture->draw(ci,Point2());
break;
*/
Size2i s;
Rect2i src_rect;
if (region) {
s=region_rect.size;
src_rect=region_rect;
} else {
s = texture->get_size();
s=s/Size2i(hframes,vframes);
src_rect.size=s;
src_rect.pos.x+=(frame%hframes)*s.x;
src_rect.pos.y+=(frame/hframes)*s.y;
}
Point2i ofs=offset;
if (centered)
ofs-=s/2;
Rect2i dst_rect(ofs,s);
if (hflip)
dst_rect.size.x=-dst_rect.size.x;
if (vflip)
dst_rect.size.y=-dst_rect.size.y;
texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
} break;
}
}
void Sprite::set_texture(const Ref<Texture>& p_texture) {
if (p_texture==texture)
return;
if (texture.is_valid()) {
texture->disconnect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update);
}
texture=p_texture;
if (texture.is_valid()) {
texture->set_flags(texture->get_flags()&(~Texture::FLAG_REPEAT)); //remove repeat from texture, it looks bad in sprites
texture->connect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update);
}
update();
item_rect_changed();
}
Ref<Texture> Sprite::get_texture() const {
return texture;
}
void Sprite::set_centered(bool p_center) {
centered=p_center;
update();
item_rect_changed();
}
bool Sprite::is_centered() const {
return centered;
}
void Sprite::set_offset(const Point2& p_offset) {
offset=p_offset;
update();
item_rect_changed();
}
Point2 Sprite::get_offset() const {
return offset;
}
void Sprite::set_flip_h(bool p_flip) {
hflip=p_flip;
update();
}
bool Sprite::is_flipped_h() const {
return hflip;
}
void Sprite::set_flip_v(bool p_flip) {
vflip=p_flip;
update();
}
bool Sprite::is_flipped_v() const {
return vflip;
}
void Sprite::set_region(bool p_region) {
if (p_region==region)
return;
region=p_region;
update();
}
bool Sprite::is_region() const{
return region;
}
void Sprite::set_region_rect(const Rect2& p_region_rect) {
bool changed=region_rect!=p_region_rect;
region_rect=p_region_rect;
if (region && changed) {
update();
item_rect_changed();
}
}
Rect2 Sprite::get_region_rect() const {
return region_rect;
}
void Sprite::set_frame(int p_frame) {
ERR_FAIL_INDEX(p_frame,vframes*hframes);
if (frame != p_frame)
item_rect_changed();
frame=p_frame;
}
int Sprite::get_frame() const {
return frame;
}
void Sprite::set_vframes(int p_amount) {
ERR_FAIL_COND(p_amount<1);
vframes=p_amount;
update();
item_rect_changed();
_change_notify("frame");
}
int Sprite::get_vframes() const {
return vframes;
}
void Sprite::set_hframes(int p_amount) {
ERR_FAIL_COND(p_amount<1);
hframes=p_amount;
update();
item_rect_changed();
_change_notify("frame");
}
int Sprite::get_hframes() const {
return hframes;
}
void Sprite::set_modulate(const Color& p_color) {
modulate=p_color;
update();
}
Color Sprite::get_modulate() const{
return modulate;
}
Rect2 Sprite::get_item_rect() const {
if (texture.is_null())
return Rect2(0,0,1,1);
//if (texture.is_null())
// return CanvasItem::get_item_rect();
Size2i s;
if (region) {
s=region_rect.size;
} else {
s = texture->get_size();
s=s/Point2(hframes,vframes);
}
Point2i ofs=offset;
if (centered)
ofs-=s/2;
if (s==Size2(0,0))
s=Size2(1,1);
return Rect2(ofs,s);
}
void Sprite::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_texture","texture:Texture"),&Sprite::set_texture);
ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&Sprite::get_texture);
ObjectTypeDB::bind_method(_MD("set_centered","centered"),&Sprite::set_centered);
ObjectTypeDB::bind_method(_MD("is_centered"),&Sprite::is_centered);
ObjectTypeDB::bind_method(_MD("set_offset","offset"),&Sprite::set_offset);
ObjectTypeDB::bind_method(_MD("get_offset"),&Sprite::get_offset);
ObjectTypeDB::bind_method(_MD("set_flip_h","flip_h"),&Sprite::set_flip_h);
ObjectTypeDB::bind_method(_MD("is_flipped_h"),&Sprite::is_flipped_h);
ObjectTypeDB::bind_method(_MD("set_flip_v","flip_v"),&Sprite::set_flip_v);
ObjectTypeDB::bind_method(_MD("is_flipped_v"),&Sprite::is_flipped_v);
ObjectTypeDB::bind_method(_MD("set_region","enabled"),&Sprite::set_region);
ObjectTypeDB::bind_method(_MD("is_region"),&Sprite::is_region);
ObjectTypeDB::bind_method(_MD("set_region_rect","rect"),&Sprite::set_region_rect);
ObjectTypeDB::bind_method(_MD("get_region_rect"),&Sprite::get_region_rect);
ObjectTypeDB::bind_method(_MD("set_frame","frame"),&Sprite::set_frame);
ObjectTypeDB::bind_method(_MD("get_frame"),&Sprite::get_frame);
ObjectTypeDB::bind_method(_MD("set_vframes","vframes"),&Sprite::set_vframes);
ObjectTypeDB::bind_method(_MD("get_vframes"),&Sprite::get_vframes);
ObjectTypeDB::bind_method(_MD("set_hframes","hframes"),&Sprite::set_hframes);
ObjectTypeDB::bind_method(_MD("get_hframes"),&Sprite::get_hframes);
ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&Sprite::set_modulate);
ObjectTypeDB::bind_method(_MD("get_modulate"),&Sprite::get_modulate);
ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame"));
ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region"));
ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect"));
}
Sprite::Sprite() {
centered=true;
hflip=false;
vflip=false;
region=false;
frame=0;
vframes=1;
hframes=1;
modulate=Color(1,1,1,1);
}

108
scene/2d/sprite.h Normal file
View File

@ -0,0 +1,108 @@
/*************************************************************************/
/* sprite.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 SPRITE_H
#define SPRITE_H
#include "scene/2d/node_2d.h"
#include "scene/resources/texture.h"
class Sprite : public Node2D {
OBJ_TYPE( Sprite, Node2D );
Ref<Texture> texture;
bool centered;
Point2 offset;
bool hflip;
bool vflip;
bool region;
Rect2 region_rect;
int frame;
int vframes;
int hframes;
Color modulate;
protected:
void _notification(int p_what);
static void _bind_methods();;
public:
virtual void edit_set_pivot(const Point2& p_pivot);
virtual Point2 edit_get_pivot() const;
virtual bool edit_has_pivot() const;
void set_texture(const Ref<Texture>& p_texture);
Ref<Texture> get_texture() const;
void set_centered(bool p_center);
bool is_centered() const;
void set_offset(const Point2& p_offset);
Point2 get_offset() const;
void set_flip_h(bool p_flip);
bool is_flipped_h() const;
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
void set_region(bool p_region);
bool is_region() const;
void set_region_rect(const Rect2& p_region_rect);
Rect2 get_region_rect() const;
void set_frame(int p_frame);
int get_frame() const;
void set_vframes(int p_amount);
int get_vframes() const;
void set_hframes(int p_amount);
int get_hframes() const;
void set_modulate(const Color& p_color);
Color get_modulate() const;
virtual Rect2 get_item_rect() const;
Sprite();
};
#endif // SPRITE_H

592
scene/2d/tile_map.cpp Normal file
View File

@ -0,0 +1,592 @@
/*************************************************************************/
/* tile_map.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 "tile_map.h"
#include "io/marshalls.h"
#include "servers/physics_2d_server.h"
void TileMap::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_SCENE: {
pending_update=true;
_update_dirty_quadrants();
RID space = get_world_2d()->get_space();
_update_quadrant_transform();
_update_quadrant_space(space);
} break;
case NOTIFICATION_EXIT_SCENE: {
_update_quadrant_space(RID());
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
//move stuff
_update_quadrant_transform();
} break;
}
}
void TileMap::_update_quadrant_space(const RID& p_space) {
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
Quadrant &q=E->get();
Physics2DServer::get_singleton()->body_set_space(q.static_body,p_space);
}
}
void TileMap::_update_quadrant_transform() {
if (!is_inside_scene())
return;
Matrix32 global_transform = get_global_transform();
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
Quadrant &q=E->get();
Matrix32 xform;
xform.set_origin( q.pos );
xform = global_transform * xform;
Physics2DServer::get_singleton()->body_set_state(q.static_body,Physics2DServer::BODY_STATE_TRANSFORM,xform);
}
}
void TileMap::set_tileset(const Ref<TileSet>& p_tileset) {
if (tile_set.is_valid())
tile_set->disconnect("changed",this,"_recreate_quadrants");
_clear_quadrants();
tile_set=p_tileset;
if (tile_set.is_valid())
tile_set->connect("changed",this,"_recreate_quadrants");
else
clear();
_recreate_quadrants();
}
Ref<TileSet> TileMap::get_tileset() const {
return tile_set;
}
void TileMap::set_cell_size(int p_size) {
ERR_FAIL_COND(p_size<1);
_clear_quadrants();
cell_size=p_size;
_recreate_quadrants();
}
int TileMap::get_cell_size() const {
return cell_size;
}
void TileMap::set_quadrant_size(int p_size) {
ERR_FAIL_COND(p_size<1);
_clear_quadrants();
quadrant_size=p_size;
_recreate_quadrants();
}
int TileMap::get_quadrant_size() const {
return quadrant_size;
}
void TileMap::set_center_x(bool p_enable) {
center_x=p_enable;
_recreate_quadrants();
}
bool TileMap::get_center_x() const {
return center_x;
}
void TileMap::set_center_y(bool p_enable) {
center_y=p_enable;
_recreate_quadrants();
}
bool TileMap::get_center_y() const {
return center_y;
}
void TileMap::_update_dirty_quadrants() {
if (!pending_update)
return;
if (!is_inside_scene())
return;
if (!tile_set.is_valid())
return;
VisualServer *vs = VisualServer::get_singleton();
Physics2DServer *ps = Physics2DServer::get_singleton();
while (dirty_quadrant_list.first()) {
Quadrant &q = *dirty_quadrant_list.first()->self();
vs->canvas_item_clear(q.canvas_item);
ps->body_clear_shapes(q.static_body);
for(int i=0;i<q.cells.size();i++) {
Map<PosKey,Cell>::Element *E=tile_map.find( q.cells[i] );
Cell &c=E->get();
//moment of truth
if (!tile_set->has_tile(c.id))
continue;
Ref<Texture> tex = tile_set->tile_get_texture(c.id);
Vector2 tile_ofs = tile_set->tile_get_offset(c.id);
Vector2 offset = Point2( E->key().x, E->key().y )*cell_size - q.pos;
if (!tex.is_valid())
continue;
Rect2 r = tile_set->tile_get_region(c.id);
Size2 s = tex->get_size();
if (r==Rect2())
s = tex->get_size();
else {
s = r.size;
r.pos.x+=fp_adjust;
r.pos.y+=fp_adjust;
r.size.x-=fp_adjust*2.0;
r.size.y-=fp_adjust*2.0;
}
Rect2 rect;
rect.pos=offset.floor();
rect.size=s;
rect.size.x+=fp_adjust;
rect.size.y+=fp_adjust;
if (c.flip_h)
rect.size.x=-rect.size.x;
if (c.flip_v)
rect.size.y=-rect.size.y;
if (r==Rect2()) {
tex->draw_rect(q.canvas_item,rect);
} else {
tex->draw_rect_region(q.canvas_item,rect,r);
}
Vector< Ref<Shape2D> > shapes = tile_set->tile_get_shapes(c.id);
for(int i=0;i<shapes.size();i++) {
Ref<Shape2D> shape = shapes[i];
if (shape.is_valid()) {
Matrix32 xform;
xform.set_origin(offset.floor());
if (c.flip_h) {
xform.elements[0]=-xform.elements[0];
xform.elements[2].x+=s.x;
}
if (c.flip_v) {
xform.elements[1]=-xform.elements[1];
xform.elements[2].y+=s.y;
}
ps->body_add_shape(q.static_body,shape->get_rid(),xform);
}
}
}
dirty_quadrant_list.remove( dirty_quadrant_list.first() );
}
pending_update=false;
_recompute_rect_cache();
}
void TileMap::_recompute_rect_cache() {
#ifdef DEBUG_ENABLED
if (!rect_cache_dirty)
return;
Rect2 r_total;
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
Rect2 r( Point2(E->key().x, E->key().y)*cell_size*quadrant_size, Size2(1,1)*cell_size*quadrant_size );
if (E==quadrant_map.front())
r_total=r;
else
r_total=r_total.merge(r);
}
if (r_total==Rect2()) {
rect_cache=Rect2(-10,-10,20,20);
} else {
rect_cache=r_total;
}
item_rect_changed();
rect_cache_dirty=false;
#endif
}
Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const PosKey& p_qk) {
Matrix32 xform;
xform.set_origin(Point2(p_qk.x,p_qk.y)*quadrant_size*cell_size);
Quadrant q;
q.canvas_item = VisualServer::get_singleton()->canvas_item_create();
VisualServer::get_singleton()->canvas_item_set_parent( q.canvas_item, get_canvas_item() );
VisualServer::get_singleton()->canvas_item_set_transform( q.canvas_item, xform );
q.static_body=Physics2DServer::get_singleton()->body_create(Physics2DServer::BODY_MODE_STATIC);
if (is_inside_scene()) {
xform = get_global_transform() * xform;
RID space = get_world_2d()->get_space();
Physics2DServer::get_singleton()->body_set_space(q.static_body,space);
}
Physics2DServer::get_singleton()->body_set_state(q.static_body,Physics2DServer::BODY_STATE_TRANSFORM,xform);
q.pos=Vector2(p_qk.x,p_qk.y)*quadrant_size*cell_size;
rect_cache_dirty=true;
return quadrant_map.insert(p_qk,q);
}
void TileMap::_erase_quadrant(Map<PosKey,Quadrant>::Element *Q) {
Quadrant &q=Q->get();
Physics2DServer::get_singleton()->free(q.static_body);
VisualServer::get_singleton()->free(q.canvas_item);
if (q.dirty_list.in_list())
dirty_quadrant_list.remove(&q.dirty_list);
quadrant_map.erase(Q);
rect_cache_dirty=true;
}
void TileMap::_make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q) {
Quadrant &q=Q->get();
if (!q.dirty_list.in_list())
dirty_quadrant_list.add(&q.dirty_list);
if (pending_update)
return;
pending_update=true;
if (!is_inside_scene())
return;
call_deferred("_update_dirty_quadrants");
}
void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
PosKey pk(p_x,p_y);
Map<PosKey,Cell>::Element *E=tile_map.find(pk);
if (!E && p_tile==INVALID_CELL)
return; //nothing to do
PosKey qk(p_x/quadrant_size,p_y/quadrant_size);
if (p_tile==INVALID_CELL) {
//erase existing
tile_map.erase(pk);
Map<PosKey,Quadrant>::Element *Q = quadrant_map.find(qk);
ERR_FAIL_COND(!Q);
Quadrant &q=Q->get();
q.cells.erase(pk);
if (q.cells.size()==0)
_erase_quadrant(Q);
else
_make_quadrant_dirty(Q);
return;
}
Map<PosKey,Quadrant>::Element *Q = quadrant_map.find(qk);
if (!E) {
E=tile_map.insert(pk,Cell());
if (!Q)
Q=_create_quadrant(qk);
Quadrant &q=Q->get();
q.cells.insert(pk);
} else {
ERR_FAIL_COND(!Q); // quadrant should exist...
if (E->get().id==p_tile && E->get().flip_h==p_flip_x && E->get().flip_v==p_flip_y)
return; //nothing changed
}
Cell &c = E->get();
c.id=p_tile;
c.flip_h=p_flip_x;
c.flip_v=p_flip_y;
_make_quadrant_dirty(Q);
}
int TileMap::get_cell(int p_x,int p_y) const {
PosKey pk(p_x,p_y);
const Map<PosKey,Cell>::Element *E=tile_map.find(pk);
if (!E)
return INVALID_CELL;
return E->get().id;
}
bool TileMap::is_cell_x_flipped(int p_x,int p_y) const {
PosKey pk(p_x,p_y);
const Map<PosKey,Cell>::Element *E=tile_map.find(pk);
if (!E)
return false;
return E->get().flip_h;
}
bool TileMap::is_cell_y_flipped(int p_x,int p_y) const {
PosKey pk(p_x,p_y);
const Map<PosKey,Cell>::Element *E=tile_map.find(pk);
if (!E)
return false;
return E->get().flip_v;
}
void TileMap::_recreate_quadrants() {
_clear_quadrants();
for (Map<PosKey,Cell>::Element *E=tile_map.front();E;E=E->next()) {
PosKey qk(E->key().x/quadrant_size,E->key().y/quadrant_size);
Map<PosKey,Quadrant>::Element *Q=quadrant_map.find(qk);
if (!Q) {
Q=_create_quadrant(qk);
dirty_quadrant_list.add(&Q->get().dirty_list);
}
Q->get().cells.insert(E->key());
}
}
void TileMap::_clear_quadrants() {
while (quadrant_map.size()) {
_erase_quadrant( quadrant_map.front() );
}
}
void TileMap::clear() {
_clear_quadrants();
tile_map.clear();
}
void TileMap::_set_tile_data(const DVector<int>& p_data) {
int c=p_data.size();
DVector<int>::Read r = p_data.read();
for(int i=0;i<c;i+=2) {
const uint8_t *ptr=(const uint8_t*)&r[i];
uint8_t local[8];
for(int j=0;j<8;j++)
local[j]=ptr[j];
#ifdef BIG_ENDIAN_ENABLED
SWAP(local[0],local[3]);
SWAP(local[1],local[2]);
SWAP(local[4],local[7]);
SWAP(local[5],local[6]);
#endif
int x = decode_uint16(&local[0]);
int y = decode_uint16(&local[2]);
uint32_t v = decode_uint32(&local[4]);
bool flip_h = v&(1<<29);
bool flip_v = v&(1<<30);
v&=(1<<29)-1;
// if (x<-20 || y <-20 || x>4000 || y>4000)
// continue;
set_cell(x,y,v,flip_h,flip_v);
}
}
DVector<int> TileMap::_get_tile_data() const {
DVector<int> data;
data.resize(tile_map.size()*2);
DVector<int>::Write w = data.write();
int idx=0;
for(const Map<PosKey,Cell>::Element *E=tile_map.front();E;E=E->next()) {
uint8_t *ptr = (uint8_t*)&w[idx];
encode_uint16(E->key().x,&ptr[0]);
encode_uint16(E->key().y,&ptr[2]);
uint32_t val = E->get().id;
if (E->get().flip_h)
val|=(1<<29);
if (E->get().flip_v)
val|=(1<<30);
encode_uint32(val,&ptr[4]);
idx+=2;
}
w = DVector<int>::Write();
return data;
}
Rect2 TileMap::get_item_rect() const {
const_cast<TileMap*>(this)->_update_dirty_quadrants();
return rect_cache;
}
void TileMap::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_tileset","tileset:TileSet"),&TileMap::set_tileset);
ObjectTypeDB::bind_method(_MD("get_tileset:TileSet"),&TileMap::get_tileset);
ObjectTypeDB::bind_method(_MD("set_cell_size","size"),&TileMap::set_cell_size);
ObjectTypeDB::bind_method(_MD("get_cell_size"),&TileMap::get_cell_size);
ObjectTypeDB::bind_method(_MD("set_quadrant_size","size"),&TileMap::set_quadrant_size);
ObjectTypeDB::bind_method(_MD("get_quadrant_size"),&TileMap::get_quadrant_size);
ObjectTypeDB::bind_method(_MD("set_center_x","enable"),&TileMap::set_center_x);
ObjectTypeDB::bind_method(_MD("get_center_x"),&TileMap::get_center_x);
ObjectTypeDB::bind_method(_MD("set_center_y","enable"),&TileMap::set_center_y);
ObjectTypeDB::bind_method(_MD("get_center_y"),&TileMap::get_center_y);
ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_cell","x","y"),&TileMap::get_cell);
ObjectTypeDB::bind_method(_MD("is_cell_x_flipped","x","y"),&TileMap::is_cell_x_flipped);
ObjectTypeDB::bind_method(_MD("is_cell_y_flipped","x","y"),&TileMap::is_cell_y_flipped);
ObjectTypeDB::bind_method(_MD("clear"),&TileMap::clear);
ObjectTypeDB::bind_method(_MD("_clear_quadrants"),&TileMap::_clear_quadrants);
ObjectTypeDB::bind_method(_MD("_recreate_quadrants"),&TileMap::_recreate_quadrants);
ObjectTypeDB::bind_method(_MD("_update_dirty_quadrants"),&TileMap::_update_dirty_quadrants);
ObjectTypeDB::bind_method(_MD("_set_tile_data"),&TileMap::_set_tile_data);
ObjectTypeDB::bind_method(_MD("_get_tile_data"),&TileMap::_get_tile_data);
ADD_PROPERTY( PropertyInfo(Variant::INT,"cell_size",PROPERTY_HINT_RANGE,"1,8192,1"),_SCS("set_cell_size"),_SCS("get_cell_size"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"quadrant_size",PROPERTY_HINT_RANGE,"1,128,1"),_SCS("set_quadrant_size"),_SCS("get_quadrant_size"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_set",PROPERTY_HINT_RESOURCE_TYPE,"TileSet"),_SCS("set_tileset"),_SCS("get_tileset"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_tile_data"),_SCS("_get_tile_data"));
BIND_CONSTANT( INVALID_CELL );
}
TileMap::TileMap() {
rect_cache_dirty=true;
pending_update=false;
quadrant_size=16;
cell_size=64;
center_x=false;
center_y=false;
fp_adjust=0.4;
fp_adjust=0.4;
}
TileMap::~TileMap() {
clear();
}

154
scene/2d/tile_map.h Normal file
View File

@ -0,0 +1,154 @@
/*************************************************************************/
/* tile_map.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 TILE_MAP_H
#define TILE_MAP_H
#include "scene/2d/node_2d.h"
#include "scene/resources/tile_set.h"
#include "self_list.h"
#include "vset.h"
class TileMap : public Node2D {
OBJ_TYPE( TileMap, Node2D );
Ref<TileSet> tile_set;
int cell_size;
int quadrant_size;
bool center_x,center_y;
union PosKey {
struct {
int16_t x;
int16_t y;
};
uint32_t key;
bool operator<(const PosKey& pk) const { return key<pk.key; }
PosKey(int16_t p_x, int16_t p_y) { x=p_x; y=p_y; }
PosKey() { key=0; }
};
union Cell {
struct {
int32_t id:24;
bool flip_h:1;
bool flip_v:1;
};
uint32_t _u32t;
Cell() { _u32t=0; }
};
Map<PosKey,Cell> tile_map;
struct Quadrant {
Vector2 pos;
RID canvas_item;
RID static_body;
SelfList<Quadrant> dirty_list;
VSet<PosKey> cells;
void operator=(const Quadrant& q) { pos=q.pos; canvas_item=q.canvas_item; static_body=q.static_body; cells=q.cells; }
Quadrant(const Quadrant& q) : dirty_list(this) { pos=q.pos; canvas_item=q.canvas_item; static_body=q.static_body; cells=q.cells;}
Quadrant() : dirty_list(this) {}
};
Map<PosKey,Quadrant> quadrant_map;
SelfList<Quadrant>::List dirty_quadrant_list;
bool pending_update;
Rect2 rect_cache;
bool rect_cache_dirty;
float fp_adjust;
Map<PosKey,Quadrant>::Element *_create_quadrant(const PosKey& p_qk);
void _erase_quadrant(Map<PosKey,Quadrant>::Element *Q);
void _make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q);
void _recreate_quadrants();
void _clear_quadrants();
void _update_dirty_quadrants();
void _update_quadrant_space(const RID& p_space);
void _update_quadrant_transform();
void _recompute_rect_cache();
void _set_tile_data(const DVector<int>& p_data);
DVector<int> _get_tile_data() const;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
enum {
INVALID_CELL=-1
};
void set_tileset(const Ref<TileSet>& p_tileset);
Ref<TileSet> get_tileset() const;
void set_cell_size(int p_size);
int get_cell_size() const;
void set_quadrant_size(int p_size);
int get_quadrant_size() const;
void set_center_x(bool p_enable);
bool get_center_x() const;
void set_center_y(bool p_enable);
bool get_center_y() const;
void set_cell(int p_x,int p_y,int p_tile,bool p_flip_x=false,bool p_flip_y=false);
int get_cell(int p_x,int p_y) const;
bool is_cell_x_flipped(int p_x,int p_y) const;
bool is_cell_y_flipped(int p_x,int p_y) const;
Rect2 get_item_rect() const;
void clear();
TileMap();
~TileMap();
};
#endif // TILE_MAP_H

View File

@ -0,0 +1,322 @@
/*************************************************************************/
/* visibility_notifier_2d.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_2d.h"
#include "scene/scene_string_names.h"
#include "scene/2d/physics_body_2d.h"
#include "scene/animation/animation_player.h"
#include "scene/scene_string_names.h"
void VisibilityNotifier2D::_enter_viewport(Viewport* p_viewport) {
ERR_FAIL_COND(viewports.has(p_viewport));
viewports.insert(p_viewport);
if (viewports.size()==1) {
emit_signal(SceneStringNames::get_singleton()->enter_screen);
_screen_enter();
}
emit_signal(SceneStringNames::get_singleton()->enter_viewport,p_viewport);
}
void VisibilityNotifier2D::_exit_viewport(Viewport* p_viewport){
ERR_FAIL_COND(!viewports.has(p_viewport));
viewports.erase(p_viewport);
emit_signal(SceneStringNames::get_singleton()->exit_viewport,p_viewport);
if (viewports.size()==0) {
emit_signal(SceneStringNames::get_singleton()->exit_screen);
_screen_exit();
}
}
void VisibilityNotifier2D::set_rect(const Rect2& p_rect){
rect=p_rect;
if (is_inside_scene())
get_world_2d()->_update_notifier(this,get_global_transform().xform(rect));
_change_notify("rect");
}
Rect2 VisibilityNotifier2D::get_item_rect() const {
return rect;
}
Rect2 VisibilityNotifier2D::get_rect() const{
return rect;
}
void VisibilityNotifier2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_SCENE: {
//get_world_2d()->
get_world_2d()->_register_notifier(this,get_global_transform().xform(rect));
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
//get_world_2d()->
get_world_2d()->_update_notifier(this,get_global_transform().xform(rect));
} break;
case NOTIFICATION_DRAW: {
if (get_scene()->is_editor_hint()) {
draw_rect(rect,Color(1,0.5,1,0.2));
}
} break;
case NOTIFICATION_EXIT_SCENE: {
get_world_2d()->_remove_notifier(this);
} break;
}
}
bool VisibilityNotifier2D::is_on_screen() const {
return viewports.size()>0;
}
void VisibilityNotifier2D::_bind_methods(){
ObjectTypeDB::bind_method(_MD("set_rect","rect"),&VisibilityNotifier2D::set_rect);
ObjectTypeDB::bind_method(_MD("get_rect"),&VisibilityNotifier2D::get_rect);
ObjectTypeDB::bind_method(_MD("is_on_screen"),&VisibilityNotifier2D::is_on_screen);
ADD_PROPERTY( PropertyInfo(Variant::RECT2,"rect"),_SCS("set_rect"),_SCS("get_rect"));
ADD_SIGNAL( MethodInfo("enter_viewport",PropertyInfo(Variant::OBJECT,"viewport",PROPERTY_HINT_RESOURCE_TYPE,"Viewport")) );
ADD_SIGNAL( MethodInfo("exit_viewport",PropertyInfo(Variant::OBJECT,"viewport",PROPERTY_HINT_RESOURCE_TYPE,"Viewport")) );
ADD_SIGNAL( MethodInfo("enter_screen"));
ADD_SIGNAL( MethodInfo("exit_screen"));
}
VisibilityNotifier2D::VisibilityNotifier2D() {
rect=Rect2(-10,-10,20,20);
}
//////////////////////////////////////
void VisibilityEnabler2D::_screen_enter() {
for(Map<Node*,Variant>::Element *E=nodes.front();E;E=E->next()) {
_change_node_state(E->key(),true);
}
visible=true;
}
void VisibilityEnabler2D::_screen_exit(){
for(Map<Node*,Variant>::Element *E=nodes.front();E;E=E->next()) {
_change_node_state(E->key(),false);
}
visible=false;
}
void VisibilityEnabler2D::_find_nodes(Node* p_node) {
bool add=false;
Variant meta;
if (enabler[ENABLER_FREEZE_BODIES]) {
RigidBody2D *rb2d = p_node->cast_to<RigidBody2D>();
if (rb2d && ((rb2d->get_mode()==RigidBody2D::MODE_CHARACTER || (rb2d->get_mode()==RigidBody2D::MODE_RIGID && !rb2d->is_able_to_sleep())))) {
add=true;
meta=rb2d->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 VisibilityEnabler2D::_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 VisibilityEnabler2D::_change_node_state(Node* p_node,bool p_enabled) {
ERR_FAIL_COND(!nodes.has(p_node));
{
RigidBody2D *rb = p_node->cast_to<RigidBody2D>();
if (rb) {
if (p_enabled) {
RigidBody2D::Mode mode = RigidBody2D::Mode(nodes[p_node].operator int());
//rb->set_mode(mode);
rb->set_active(true);
} else {
//rb->set_mode(RigidBody2D::MODE_STATIC);
rb->set_active(false);
}
}
}
{
AnimationPlayer *ap=p_node->cast_to<AnimationPlayer>();
if (ap) {
ap->set_active(p_enabled);
}
}
}
void VisibilityEnabler2D::_node_removed(Node* p_node) {
if (!visible)
_change_node_state(p_node,true);
//changed to one shot, not needed
//p_node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed");
nodes.erase(p_node);
}
void VisibilityEnabler2D::_bind_methods(){
ObjectTypeDB::bind_method(_MD("set_enabler","enabler","enabled"),&VisibilityEnabler2D::set_enabler);
ObjectTypeDB::bind_method(_MD("is_enabler_enabled","enabler"),&VisibilityEnabler2D::is_enabler_enabled);
ObjectTypeDB::bind_method(_MD("_node_removed"),&VisibilityEnabler2D::_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 VisibilityEnabler2D::set_enabler(Enabler p_enabler,bool p_enable){
ERR_FAIL_INDEX(p_enabler,ENABLER_MAX);
enabler[p_enabler]=p_enable;
}
bool VisibilityEnabler2D::is_enabler_enabled(Enabler p_enabler) const{
ERR_FAIL_INDEX_V(p_enabler,ENABLER_MAX,false);
return enabler[p_enabler];
}
VisibilityEnabler2D::VisibilityEnabler2D() {
for(int i=0;i<ENABLER_MAX;i++)
enabler[i]=true;
visible=false;
}

View File

@ -0,0 +1,109 @@
/*************************************************************************/
/* visibility_notifier_2d.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_2D_H
#define VISIBILITY_NOTIFIER_2D_H
#include "scene/2d/node_2d.h"
class Viewport;
class VisibilityNotifier2D : public Node2D {
OBJ_TYPE(VisibilityNotifier2D,Node2D);
Set<Viewport*> viewports;
Rect2 rect;
protected:
friend class SpatialIndexer2D;
void _enter_viewport(Viewport* p_viewport);
void _exit_viewport(Viewport* p_viewport);
virtual void _screen_enter() {}
virtual void _screen_exit() {}
void _notification(int p_what);
static void _bind_methods();
public:
void set_rect(const Rect2& p_rect);
Rect2 get_rect() const;
bool is_on_screen() const;
virtual Rect2 get_item_rect() const;
VisibilityNotifier2D();
};
class VisibilityEnabler2D : public VisibilityNotifier2D {
OBJ_TYPE(VisibilityEnabler2D,VisibilityNotifier2D);
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;
VisibilityEnabler2D();
};
VARIANT_ENUM_CAST(VisibilityEnabler2D::Enabler);
#endif // VISIBILITY_NOTIFIER_2D_H

14
scene/3d/SCsub Normal file
View File

@ -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')

317
scene/3d/area.cpp Normal file
View File

@ -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() {
}

121
scene/3d/area.h Normal file
View File

@ -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

829
scene/3d/body_shape.cpp Normal file
View File

@ -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

80
scene/3d/body_shape.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

727
scene/3d/camera.cpp Normal file
View File

@ -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);
}

144
scene/3d/camera.h Normal file
View File

@ -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

741
scene/3d/car_body.cpp Normal file
View File

@ -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");
}

170
scene/3d/car_body.h Normal file
View File

@ -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

View File

@ -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

167
scene/3d/character_camera.h Normal file
View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

73
scene/3d/editable_shape.h Normal file
View File

@ -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

778
scene/3d/follow_camera.cpp Normal file
View File

@ -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);
}
}

180
scene/3d/follow_camera.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

585
scene/3d/light.cpp Normal file
View File

@ -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 );
}

195
scene/3d/light.h Normal file
View File

@ -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

218
scene/3d/mesh_instance.cpp Normal file
View File

@ -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() {
}

80
scene/3d/mesh_instance.h Normal file
View File

@ -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

View File

@ -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() {
}

View File

@ -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

View File

@ -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()
{
}

View File

@ -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

559
scene/3d/particles.cpp Normal file
View File

@ -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);
}

165
scene/3d/particles.h Normal file
View File

@ -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

388
scene/3d/path.cpp Normal file
View File

@ -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;
}

122
scene/3d/path.h Normal file
View File

@ -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

741
scene/3d/physics_body.cpp Normal file
View File

@ -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 );
}

219
scene/3d/physics_body.h Normal file
View File

@ -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

327
scene/3d/physics_joint.cpp Normal file
View File

@ -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

104
scene/3d/physics_joint.h Normal file
View File

@ -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

281
scene/3d/portal.cpp Normal file
View File

@ -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);
}

93
scene/3d/portal.h Normal file
View File

@ -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

66
scene/3d/position_3d.cpp Normal file
View File

@ -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()
{
}

45
scene/3d/position_3d.h Normal file
View File

@ -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

View File

@ -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() {
};

View File

@ -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

232
scene/3d/quad.cpp Normal file
View File

@ -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;
}

76
scene/3d/quad.h Normal file
View File

@ -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

190
scene/3d/ray_cast.cpp Normal file
View File

@ -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);
}

72
scene/3d/ray_cast.h Normal file
View File

@ -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

299
scene/3d/room_instance.cpp Normal file
View File

@ -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);
}

102
scene/3d/room_instance.h Normal file
View File

@ -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

74
scene/3d/scenario_fx.cpp Normal file
View File

@ -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() {
}

58
scene/3d/scenario_fx.h Normal file
View File

@ -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

Some files were not shown because too many files have changed in this diff Show More