sprite_3d.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. /*************************************************************************/
  2. /* sprite_3d.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "sprite_3d.h"
  31. #include "core_string_names.h"
  32. #include "scene/scene_string_names.h"
  33. Color SpriteBase3D::_get_color_accum() {
  34. if (!color_dirty)
  35. return color_accum;
  36. if (parent_sprite)
  37. color_accum = parent_sprite->_get_color_accum();
  38. else
  39. color_accum = Color(1, 1, 1, 1);
  40. color_accum.r *= modulate.r;
  41. color_accum.g *= modulate.g;
  42. color_accum.b *= modulate.b;
  43. color_accum.a *= modulate.a;
  44. color_dirty = false;
  45. return color_accum;
  46. }
  47. void SpriteBase3D::_propagate_color_changed() {
  48. if (color_dirty)
  49. return;
  50. color_dirty = true;
  51. _queue_update();
  52. for (List<SpriteBase3D *>::Element *E = children.front(); E; E = E->next()) {
  53. E->get()->_propagate_color_changed();
  54. }
  55. }
  56. void SpriteBase3D::_notification(int p_what) {
  57. if (p_what == NOTIFICATION_ENTER_TREE) {
  58. if (!pending_update)
  59. _im_update();
  60. parent_sprite = Object::cast_to<SpriteBase3D>(get_parent());
  61. if (parent_sprite) {
  62. pI = parent_sprite->children.push_back(this);
  63. }
  64. }
  65. if (p_what == NOTIFICATION_EXIT_TREE) {
  66. if (parent_sprite) {
  67. parent_sprite->children.erase(pI);
  68. pI = NULL;
  69. parent_sprite = NULL;
  70. }
  71. }
  72. }
  73. void SpriteBase3D::set_centered(bool p_center) {
  74. centered = p_center;
  75. _queue_update();
  76. }
  77. bool SpriteBase3D::is_centered() const {
  78. return centered;
  79. }
  80. void SpriteBase3D::set_offset(const Point2 &p_offset) {
  81. offset = p_offset;
  82. _queue_update();
  83. }
  84. Point2 SpriteBase3D::get_offset() const {
  85. return offset;
  86. }
  87. void SpriteBase3D::set_flip_h(bool p_flip) {
  88. hflip = p_flip;
  89. _queue_update();
  90. }
  91. bool SpriteBase3D::is_flipped_h() const {
  92. return hflip;
  93. }
  94. void SpriteBase3D::set_flip_v(bool p_flip) {
  95. vflip = p_flip;
  96. _queue_update();
  97. }
  98. bool SpriteBase3D::is_flipped_v() const {
  99. return vflip;
  100. }
  101. void SpriteBase3D::set_modulate(const Color &p_color) {
  102. modulate = p_color;
  103. _propagate_color_changed();
  104. _queue_update();
  105. }
  106. Color SpriteBase3D::get_modulate() const {
  107. return modulate;
  108. }
  109. void SpriteBase3D::set_pixel_size(float p_amount) {
  110. pixel_size = p_amount;
  111. _queue_update();
  112. }
  113. float SpriteBase3D::get_pixel_size() const {
  114. return pixel_size;
  115. }
  116. void SpriteBase3D::set_opacity(float p_amount) {
  117. opacity = p_amount;
  118. _queue_update();
  119. }
  120. float SpriteBase3D::get_opacity() const {
  121. return opacity;
  122. }
  123. void SpriteBase3D::set_axis(Vector3::Axis p_axis) {
  124. axis = p_axis;
  125. _queue_update();
  126. }
  127. Vector3::Axis SpriteBase3D::get_axis() const {
  128. return axis;
  129. }
  130. void SpriteBase3D::_im_update() {
  131. _draw();
  132. pending_update = false;
  133. //texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
  134. }
  135. void SpriteBase3D::_queue_update() {
  136. if (pending_update)
  137. return;
  138. pending_update = true;
  139. call_deferred(SceneStringNames::get_singleton()->_im_update);
  140. }
  141. Rect3 SpriteBase3D::get_aabb() const {
  142. return aabb;
  143. }
  144. PoolVector<Face3> SpriteBase3D::get_faces(uint32_t p_usage_flags) const {
  145. return PoolVector<Face3>();
  146. }
  147. void SpriteBase3D::set_draw_flag(DrawFlags p_flag, bool p_enable) {
  148. ERR_FAIL_INDEX(p_flag, FLAG_MAX);
  149. flags[p_flag] = p_enable;
  150. _queue_update();
  151. }
  152. bool SpriteBase3D::get_draw_flag(DrawFlags p_flag) const {
  153. ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
  154. return flags[p_flag];
  155. }
  156. void SpriteBase3D::set_alpha_cut_mode(AlphaCutMode p_mode) {
  157. ERR_FAIL_INDEX(p_mode, 3);
  158. alpha_cut = p_mode;
  159. _queue_update();
  160. }
  161. SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const {
  162. return alpha_cut;
  163. }
  164. void SpriteBase3D::_bind_methods() {
  165. ClassDB::bind_method(D_METHOD("set_centered", "centered"), &SpriteBase3D::set_centered);
  166. ClassDB::bind_method(D_METHOD("is_centered"), &SpriteBase3D::is_centered);
  167. ClassDB::bind_method(D_METHOD("set_offset", "offset"), &SpriteBase3D::set_offset);
  168. ClassDB::bind_method(D_METHOD("get_offset"), &SpriteBase3D::get_offset);
  169. ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &SpriteBase3D::set_flip_h);
  170. ClassDB::bind_method(D_METHOD("is_flipped_h"), &SpriteBase3D::is_flipped_h);
  171. ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &SpriteBase3D::set_flip_v);
  172. ClassDB::bind_method(D_METHOD("is_flipped_v"), &SpriteBase3D::is_flipped_v);
  173. ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &SpriteBase3D::set_modulate);
  174. ClassDB::bind_method(D_METHOD("get_modulate"), &SpriteBase3D::get_modulate);
  175. ClassDB::bind_method(D_METHOD("set_opacity", "opacity"), &SpriteBase3D::set_opacity);
  176. ClassDB::bind_method(D_METHOD("get_opacity"), &SpriteBase3D::get_opacity);
  177. ClassDB::bind_method(D_METHOD("set_pixel_size", "pixel_size"), &SpriteBase3D::set_pixel_size);
  178. ClassDB::bind_method(D_METHOD("get_pixel_size"), &SpriteBase3D::get_pixel_size);
  179. ClassDB::bind_method(D_METHOD("set_axis", "axis"), &SpriteBase3D::set_axis);
  180. ClassDB::bind_method(D_METHOD("get_axis"), &SpriteBase3D::get_axis);
  181. ClassDB::bind_method(D_METHOD("set_draw_flag", "flag", "enabled"), &SpriteBase3D::set_draw_flag);
  182. ClassDB::bind_method(D_METHOD("get_draw_flag", "flag"), &SpriteBase3D::get_draw_flag);
  183. ClassDB::bind_method(D_METHOD("set_alpha_cut_mode", "mode"), &SpriteBase3D::set_alpha_cut_mode);
  184. ClassDB::bind_method(D_METHOD("get_alpha_cut_mode"), &SpriteBase3D::get_alpha_cut_mode);
  185. ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect);
  186. ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update);
  187. ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update);
  188. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
  189. ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
  190. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
  191. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
  192. ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
  193. ADD_PROPERTY(PropertyInfo(Variant::REAL, "opacity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_opacity", "get_opacity");
  194. ADD_PROPERTY(PropertyInfo(Variant::REAL, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001"), "set_pixel_size", "get_pixel_size");
  195. ADD_PROPERTY(PropertyInfo(Variant::INT, "axis", PROPERTY_HINT_ENUM, "X-Axis,Y-Axis,Z-Axis"), "set_axis", "get_axis");
  196. ADD_GROUP("Flags", "");
  197. ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_draw_flag", "get_draw_flag", FLAG_TRANSPARENT);
  198. ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "shaded"), "set_draw_flag", "get_draw_flag", FLAG_SHADED);
  199. ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "double_sided"), "set_draw_flag", "get_draw_flag", FLAG_DOUBLE_SIDED);
  200. ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_cut", PROPERTY_HINT_ENUM, "Disabled,Discard,Opaque Pre-Pass"), "set_alpha_cut_mode", "get_alpha_cut_mode");
  201. BIND_ENUM_CONSTANT(FLAG_TRANSPARENT);
  202. BIND_ENUM_CONSTANT(FLAG_SHADED);
  203. BIND_ENUM_CONSTANT(FLAG_DOUBLE_SIDED);
  204. BIND_ENUM_CONSTANT(FLAG_MAX);
  205. BIND_ENUM_CONSTANT(ALPHA_CUT_DISABLED);
  206. BIND_ENUM_CONSTANT(ALPHA_CUT_DISCARD);
  207. BIND_ENUM_CONSTANT(ALPHA_CUT_OPAQUE_PREPASS);
  208. }
  209. SpriteBase3D::SpriteBase3D() {
  210. color_dirty = true;
  211. centered = true;
  212. hflip = false;
  213. vflip = false;
  214. parent_sprite = NULL;
  215. pI = NULL;
  216. for (int i = 0; i < FLAG_MAX; i++)
  217. flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED;
  218. axis = Vector3::AXIS_Z;
  219. pixel_size = 0.01;
  220. modulate = Color(1, 1, 1, 1);
  221. pending_update = false;
  222. opacity = 1.0;
  223. immediate = VisualServer::get_singleton()->immediate_create();
  224. set_base(immediate);
  225. }
  226. SpriteBase3D::~SpriteBase3D() {
  227. VisualServer::get_singleton()->free(immediate);
  228. }
  229. ///////////////////////////////////////////
  230. void Sprite3D::_draw() {
  231. RID immediate = get_immediate();
  232. VS::get_singleton()->immediate_clear(immediate);
  233. if (!texture.is_valid())
  234. return; //no texuture no life
  235. Vector2 tsize = texture->get_size();
  236. if (tsize.x == 0 || tsize.y == 0)
  237. return;
  238. Size2i s;
  239. Rect2i src_rect;
  240. if (region) {
  241. s = region_rect.size;
  242. src_rect = region_rect;
  243. } else {
  244. s = texture->get_size();
  245. s = s / Size2i(hframes, vframes);
  246. src_rect.size = s;
  247. src_rect.position.x += (frame % hframes) * s.x;
  248. src_rect.position.y += (frame / hframes) * s.y;
  249. }
  250. Point2i ofs = get_offset();
  251. if (is_centered())
  252. ofs -= s / 2;
  253. Rect2i dst_rect(ofs, s);
  254. Rect2 final_rect;
  255. Rect2 final_src_rect;
  256. if (!texture->get_rect_region(dst_rect, src_rect, final_rect, final_src_rect))
  257. return;
  258. if (final_rect.size.x == 0 || final_rect.size.y == 0)
  259. return;
  260. Color color = _get_color_accum();
  261. color.a *= get_opacity();
  262. float pixel_size = get_pixel_size();
  263. Vector2 vertices[4] = {
  264. (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
  265. (final_rect.position + final_rect.size) * pixel_size,
  266. (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
  267. final_rect.position * pixel_size,
  268. };
  269. Vector2 uvs[4] = {
  270. final_src_rect.position / tsize,
  271. (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / tsize,
  272. (final_src_rect.position + final_src_rect.size) / tsize,
  273. (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / tsize,
  274. };
  275. if (is_flipped_h()) {
  276. SWAP(uvs[0], uvs[1]);
  277. SWAP(uvs[2], uvs[3]);
  278. }
  279. if (is_flipped_v()) {
  280. SWAP(uvs[0], uvs[3]);
  281. SWAP(uvs[1], uvs[2]);
  282. }
  283. Vector3 normal;
  284. int axis = get_axis();
  285. normal[axis] = 1.0;
  286. RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS);
  287. VS::get_singleton()->immediate_set_material(immediate, mat);
  288. VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid());
  289. int x_axis = ((axis + 1) % 3);
  290. int y_axis = ((axis + 2) % 3);
  291. if (axis != Vector3::AXIS_Z) {
  292. SWAP(x_axis, y_axis);
  293. for (int i = 0; i < 4; i++) {
  294. //uvs[i] = Vector2(1.0,1.0)-uvs[i];
  295. //SWAP(vertices[i].x,vertices[i].y);
  296. if (axis == Vector3::AXIS_Y) {
  297. vertices[i].y = -vertices[i].y;
  298. } else if (axis == Vector3::AXIS_X) {
  299. vertices[i].x = -vertices[i].x;
  300. }
  301. }
  302. }
  303. Rect3 aabb;
  304. for (int i = 0; i < 4; i++) {
  305. VS::get_singleton()->immediate_normal(immediate, normal);
  306. VS::get_singleton()->immediate_color(immediate, color);
  307. VS::get_singleton()->immediate_uv(immediate, uvs[i]);
  308. Vector3 vtx;
  309. vtx[x_axis] = vertices[i][0];
  310. vtx[y_axis] = vertices[i][1];
  311. VS::get_singleton()->immediate_vertex(immediate, vtx);
  312. if (i == 0) {
  313. aabb.position = vtx;
  314. aabb.size = Vector3();
  315. } else {
  316. aabb.expand_to(vtx);
  317. }
  318. }
  319. set_aabb(aabb);
  320. VS::get_singleton()->immediate_end(immediate);
  321. }
  322. void Sprite3D::set_texture(const Ref<Texture> &p_texture) {
  323. if (p_texture == texture)
  324. return;
  325. if (texture.is_valid()) {
  326. texture->disconnect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->_queue_update);
  327. }
  328. texture = p_texture;
  329. if (texture.is_valid()) {
  330. texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites
  331. texture->connect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->_queue_update);
  332. }
  333. _queue_update();
  334. }
  335. Ref<Texture> Sprite3D::get_texture() const {
  336. return texture;
  337. }
  338. void Sprite3D::set_region(bool p_region) {
  339. if (p_region == region)
  340. return;
  341. region = p_region;
  342. _queue_update();
  343. }
  344. bool Sprite3D::is_region() const {
  345. return region;
  346. }
  347. void Sprite3D::set_region_rect(const Rect2 &p_region_rect) {
  348. bool changed = region_rect != p_region_rect;
  349. region_rect = p_region_rect;
  350. if (region && changed) {
  351. _queue_update();
  352. }
  353. }
  354. Rect2 Sprite3D::get_region_rect() const {
  355. return region_rect;
  356. }
  357. void Sprite3D::set_frame(int p_frame) {
  358. ERR_FAIL_INDEX(p_frame, vframes * hframes);
  359. if (frame != p_frame)
  360. frame = p_frame;
  361. _queue_update();
  362. emit_signal(SceneStringNames::get_singleton()->frame_changed);
  363. }
  364. int Sprite3D::get_frame() const {
  365. return frame;
  366. }
  367. void Sprite3D::set_vframes(int p_amount) {
  368. ERR_FAIL_COND(p_amount < 1);
  369. vframes = p_amount;
  370. _queue_update();
  371. _change_notify();
  372. }
  373. int Sprite3D::get_vframes() const {
  374. return vframes;
  375. }
  376. void Sprite3D::set_hframes(int p_amount) {
  377. ERR_FAIL_COND(p_amount < 1);
  378. hframes = p_amount;
  379. _queue_update();
  380. _change_notify();
  381. }
  382. int Sprite3D::get_hframes() const {
  383. return hframes;
  384. }
  385. Rect2 Sprite3D::get_item_rect() const {
  386. if (texture.is_null())
  387. return Rect2(0, 0, 1, 1);
  388. /*
  389. if (texture.is_null())
  390. return CanvasItem::get_item_rect();
  391. */
  392. Size2i s;
  393. if (region) {
  394. s = region_rect.size;
  395. } else {
  396. s = texture->get_size();
  397. s = s / Point2(hframes, vframes);
  398. }
  399. Point2i ofs = get_offset();
  400. if (is_centered())
  401. ofs -= s / 2;
  402. if (s == Size2(0, 0))
  403. s = Size2(1, 1);
  404. return Rect2(ofs, s);
  405. }
  406. void Sprite3D::_validate_property(PropertyInfo &property) const {
  407. if (property.name == "frame") {
  408. property.hint = PROPERTY_HINT_SPRITE_FRAME;
  409. property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
  410. }
  411. }
  412. void Sprite3D::_bind_methods() {
  413. ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite3D::set_texture);
  414. ClassDB::bind_method(D_METHOD("get_texture"), &Sprite3D::get_texture);
  415. ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite3D::set_region);
  416. ClassDB::bind_method(D_METHOD("is_region"), &Sprite3D::is_region);
  417. ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite3D::set_region_rect);
  418. ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite3D::get_region_rect);
  419. ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite3D::set_frame);
  420. ClassDB::bind_method(D_METHOD("get_frame"), &Sprite3D::get_frame);
  421. ClassDB::bind_method(D_METHOD("set_vframes", "vframes"), &Sprite3D::set_vframes);
  422. ClassDB::bind_method(D_METHOD("get_vframes"), &Sprite3D::get_vframes);
  423. ClassDB::bind_method(D_METHOD("set_hframes", "hframes"), &Sprite3D::set_hframes);
  424. ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite3D::get_hframes);
  425. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
  426. ADD_GROUP("Animation", "");
  427. ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
  428. ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
  429. ADD_PROPERTY(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
  430. ADD_GROUP("Region", "region_");
  431. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
  432. ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
  433. ADD_SIGNAL(MethodInfo("frame_changed"));
  434. }
  435. Sprite3D::Sprite3D() {
  436. region = false;
  437. frame = 0;
  438. vframes = 1;
  439. hframes = 1;
  440. }
  441. ////////////////////////////////////////
  442. void AnimatedSprite3D::_draw() {
  443. RID immediate = get_immediate();
  444. VS::get_singleton()->immediate_clear(immediate);
  445. if (frames.is_null()) {
  446. return;
  447. }
  448. if (frame < 0) {
  449. return;
  450. }
  451. if (!frames->has_animation(animation)) {
  452. return;
  453. }
  454. Ref<Texture> texture = frames->get_frame(animation, frame);
  455. if (!texture.is_valid())
  456. return; //no texuture no life
  457. Vector2 tsize = texture->get_size();
  458. if (tsize.x == 0 || tsize.y == 0)
  459. return;
  460. Size2i s = tsize;
  461. Rect2i src_rect;
  462. src_rect.size = s;
  463. Point2i ofs = get_offset();
  464. if (is_centered())
  465. ofs -= s / 2;
  466. Rect2i dst_rect(ofs, s);
  467. Rect2 final_rect;
  468. Rect2 final_src_rect;
  469. if (!texture->get_rect_region(dst_rect, src_rect, final_rect, final_src_rect))
  470. return;
  471. if (final_rect.size.x == 0 || final_rect.size.y == 0)
  472. return;
  473. Color color = _get_color_accum();
  474. color.a *= get_opacity();
  475. float pixel_size = get_pixel_size();
  476. Vector2 vertices[4] = {
  477. (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
  478. (final_rect.position + final_rect.size) * pixel_size,
  479. (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
  480. final_rect.position * pixel_size,
  481. };
  482. Vector2 uvs[4] = {
  483. final_src_rect.position / tsize,
  484. (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / tsize,
  485. (final_src_rect.position + final_src_rect.size) / tsize,
  486. (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / tsize,
  487. };
  488. if (is_flipped_h()) {
  489. SWAP(uvs[0], uvs[1]);
  490. SWAP(uvs[2], uvs[3]);
  491. }
  492. if (is_flipped_v()) {
  493. SWAP(uvs[0], uvs[3]);
  494. SWAP(uvs[1], uvs[2]);
  495. }
  496. Vector3 normal;
  497. int axis = get_axis();
  498. normal[axis] = 1.0;
  499. RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS);
  500. VS::get_singleton()->immediate_set_material(immediate, mat);
  501. VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid());
  502. int x_axis = ((axis + 1) % 3);
  503. int y_axis = ((axis + 2) % 3);
  504. if (axis != Vector3::AXIS_Z) {
  505. SWAP(x_axis, y_axis);
  506. for (int i = 0; i < 4; i++) {
  507. //uvs[i] = Vector2(1.0,1.0)-uvs[i];
  508. //SWAP(vertices[i].x,vertices[i].y);
  509. if (axis == Vector3::AXIS_Y) {
  510. vertices[i].y = -vertices[i].y;
  511. } else if (axis == Vector3::AXIS_X) {
  512. vertices[i].x = -vertices[i].x;
  513. }
  514. }
  515. }
  516. Rect3 aabb;
  517. for (int i = 0; i < 4; i++) {
  518. VS::get_singleton()->immediate_normal(immediate, normal);
  519. VS::get_singleton()->immediate_color(immediate, color);
  520. VS::get_singleton()->immediate_uv(immediate, uvs[i]);
  521. Vector3 vtx;
  522. vtx[x_axis] = vertices[i][0];
  523. vtx[y_axis] = vertices[i][1];
  524. VS::get_singleton()->immediate_vertex(immediate, vtx);
  525. if (i == 0) {
  526. aabb.position = vtx;
  527. aabb.size = Vector3();
  528. } else {
  529. aabb.expand_to(vtx);
  530. }
  531. }
  532. set_aabb(aabb);
  533. VS::get_singleton()->immediate_end(immediate);
  534. }
  535. void AnimatedSprite3D::_validate_property(PropertyInfo &property) const {
  536. if (!frames.is_valid())
  537. return;
  538. if (property.name == "animation") {
  539. property.hint = PROPERTY_HINT_ENUM;
  540. List<StringName> names;
  541. frames->get_animation_list(&names);
  542. names.sort_custom<StringName::AlphCompare>();
  543. bool current_found = false;
  544. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  545. if (E->prev()) {
  546. property.hint_string += ",";
  547. }
  548. property.hint_string += String(E->get());
  549. if (animation == E->get()) {
  550. current_found = true;
  551. }
  552. }
  553. if (!current_found) {
  554. if (property.hint_string == String()) {
  555. property.hint_string = String(animation);
  556. } else {
  557. property.hint_string = String(animation) + "," + property.hint_string;
  558. }
  559. }
  560. }
  561. if (property.name == "frame") {
  562. property.hint = PROPERTY_HINT_RANGE;
  563. if (frames->has_animation(animation)) {
  564. property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
  565. } else {
  566. property.hint_string = "0,0,0";
  567. }
  568. }
  569. }
  570. void AnimatedSprite3D::_notification(int p_what) {
  571. switch (p_what) {
  572. case NOTIFICATION_INTERNAL_PROCESS: {
  573. if (frames.is_null())
  574. return;
  575. if (!frames->has_animation(animation))
  576. return;
  577. if (frame < 0)
  578. return;
  579. float speed = frames->get_animation_speed(animation);
  580. if (speed == 0)
  581. return; //do nothing
  582. float remaining = get_process_delta_time();
  583. while (remaining) {
  584. if (timeout <= 0) {
  585. timeout = 1.0 / speed;
  586. int fc = frames->get_frame_count(animation);
  587. if (frame >= fc - 1) {
  588. if (frames->get_animation_loop(animation)) {
  589. frame = 0;
  590. } else {
  591. frame = fc - 1;
  592. }
  593. } else {
  594. frame++;
  595. }
  596. _queue_update();
  597. _change_notify("frame");
  598. }
  599. float to_process = MIN(timeout, remaining);
  600. remaining -= to_process;
  601. timeout -= to_process;
  602. }
  603. } break;
  604. }
  605. }
  606. void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
  607. if (frames.is_valid())
  608. frames->disconnect("changed", this, "_res_changed");
  609. frames = p_frames;
  610. if (frames.is_valid())
  611. frames->connect("changed", this, "_res_changed");
  612. if (!frames.is_valid()) {
  613. frame = 0;
  614. } else {
  615. set_frame(frame);
  616. }
  617. _change_notify();
  618. _reset_timeout();
  619. _queue_update();
  620. update_configuration_warning();
  621. }
  622. Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const {
  623. return frames;
  624. }
  625. void AnimatedSprite3D::set_frame(int p_frame) {
  626. if (!frames.is_valid()) {
  627. return;
  628. }
  629. if (frames->has_animation(animation)) {
  630. int limit = frames->get_frame_count(animation);
  631. if (p_frame >= limit)
  632. p_frame = limit - 1;
  633. }
  634. if (p_frame < 0)
  635. p_frame = 0;
  636. if (frame == p_frame)
  637. return;
  638. frame = p_frame;
  639. _reset_timeout();
  640. _queue_update();
  641. _change_notify("frame");
  642. emit_signal(SceneStringNames::get_singleton()->frame_changed);
  643. }
  644. int AnimatedSprite3D::get_frame() const {
  645. return frame;
  646. }
  647. Rect2 AnimatedSprite3D::get_item_rect() const {
  648. if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
  649. return Rect2(0, 0, 1, 1);
  650. }
  651. Ref<Texture> t;
  652. if (animation)
  653. t = frames->get_frame(animation, frame);
  654. if (t.is_null())
  655. return Rect2(0, 0, 1, 1);
  656. Size2i s = t->get_size();
  657. Point2 ofs = offset;
  658. if (centered)
  659. ofs -= s / 2;
  660. if (s == Size2(0, 0))
  661. s = Size2(1, 1);
  662. return Rect2(ofs, s);
  663. }
  664. void AnimatedSprite3D::_res_changed() {
  665. set_frame(frame);
  666. _change_notify("frame");
  667. _change_notify("animation");
  668. _queue_update();
  669. }
  670. void AnimatedSprite3D::_set_playing(bool p_playing) {
  671. if (playing == p_playing)
  672. return;
  673. playing = p_playing;
  674. _reset_timeout();
  675. set_process_internal(playing);
  676. }
  677. bool AnimatedSprite3D::_is_playing() const {
  678. return playing;
  679. }
  680. void AnimatedSprite3D::play(const StringName &p_animation) {
  681. if (p_animation)
  682. set_animation(p_animation);
  683. _set_playing(true);
  684. }
  685. void AnimatedSprite3D::stop() {
  686. _set_playing(false);
  687. }
  688. bool AnimatedSprite3D::is_playing() const {
  689. return is_processing();
  690. }
  691. void AnimatedSprite3D::_reset_timeout() {
  692. if (!playing)
  693. return;
  694. if (frames.is_valid() && frames->has_animation(animation)) {
  695. float speed = frames->get_animation_speed(animation);
  696. if (speed > 0) {
  697. timeout = 1.0 / speed;
  698. } else {
  699. timeout = 0;
  700. }
  701. } else {
  702. timeout = 0;
  703. }
  704. }
  705. void AnimatedSprite3D::set_animation(const StringName &p_animation) {
  706. if (animation == p_animation)
  707. return;
  708. animation = p_animation;
  709. _reset_timeout();
  710. set_frame(0);
  711. _change_notify();
  712. _queue_update();
  713. }
  714. StringName AnimatedSprite3D::get_animation() const {
  715. return animation;
  716. }
  717. String AnimatedSprite3D::get_configuration_warning() const {
  718. if (frames.is_null()) {
  719. return TTR("A SpriteFrames resource must be created or set in the 'Frames' property in order for AnimatedSprite3D to display frames.");
  720. }
  721. return String();
  722. }
  723. void AnimatedSprite3D::_bind_methods() {
  724. ClassDB::bind_method(D_METHOD("set_sprite_frames", "sprite_frames"), &AnimatedSprite3D::set_sprite_frames);
  725. ClassDB::bind_method(D_METHOD("get_sprite_frames"), &AnimatedSprite3D::get_sprite_frames);
  726. ClassDB::bind_method(D_METHOD("set_animation", "animation"), &AnimatedSprite3D::set_animation);
  727. ClassDB::bind_method(D_METHOD("get_animation"), &AnimatedSprite3D::get_animation);
  728. ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite3D::_set_playing);
  729. ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite3D::_is_playing);
  730. ClassDB::bind_method(D_METHOD("play", "anim"), &AnimatedSprite3D::play, DEFVAL(StringName()));
  731. ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite3D::stop);
  732. ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite3D::is_playing);
  733. ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite3D::set_frame);
  734. ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame);
  735. ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite3D::_res_changed);
  736. ADD_SIGNAL(MethodInfo("frame_changed"));
  737. ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
  738. ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
  739. ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
  740. ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
  741. }
  742. AnimatedSprite3D::AnimatedSprite3D() {
  743. frame = 0;
  744. playing = false;
  745. animation = "default";
  746. timeout = 0;
  747. }