2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* sprite_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* 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. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-05-29 15:56:39 +02:00
# include "sprite_3d.h"
2020-02-21 23:26:13 +01:00
2023-07-11 22:29:09 +02:00
# include "scene/resources/atlas_texture.h"
2014-05-29 15:56:39 +02:00
Color SpriteBase3D : : _get_color_accum ( ) {
2020-05-14 16:41:43 +02:00
if ( ! color_dirty ) {
2014-05-29 15:56:39 +02:00
return color_accum ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2020-05-14 16:41:43 +02:00
if ( parent_sprite ) {
2017-03-05 16:44:50 +01:00
color_accum = parent_sprite - > _get_color_accum ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2017-03-05 16:44:50 +01:00
color_accum = Color ( 1 , 1 , 1 , 1 ) ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
color_accum . r * = modulate . r ;
color_accum . g * = modulate . g ;
color_accum . b * = modulate . b ;
color_accum . a * = modulate . a ;
color_dirty = false ;
2014-05-29 15:56:39 +02:00
return color_accum ;
}
void SpriteBase3D : : _propagate_color_changed ( ) {
2020-05-14 16:41:43 +02:00
if ( color_dirty ) {
2014-05-29 15:56:39 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
color_dirty = true ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
2021-07-16 05:45:57 +02:00
for ( SpriteBase3D * & E : children ) {
E - > _propagate_color_changed ( ) ;
2014-05-29 15:56:39 +02:00
}
}
void SpriteBase3D : : _notification ( int p_what ) {
2022-02-15 18:06:48 +01:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
if ( ! pending_update ) {
_im_update ( ) ;
}
2014-05-29 15:56:39 +02:00
2022-02-15 18:06:48 +01:00
parent_sprite = Object : : cast_to < SpriteBase3D > ( get_parent ( ) ) ;
if ( parent_sprite ) {
pI = parent_sprite - > children . push_back ( this ) ;
}
} break ;
2014-05-29 15:56:39 +02:00
2022-02-15 18:06:48 +01:00
case NOTIFICATION_EXIT_TREE : {
if ( parent_sprite ) {
parent_sprite - > children . erase ( pI ) ;
pI = nullptr ;
parent_sprite = nullptr ;
}
} break ;
2014-05-29 15:56:39 +02:00
}
}
2022-09-18 20:03:03 +02:00
void SpriteBase3D : : draw_texture_rect ( Ref < Texture2D > p_texture , Rect2 p_dst_rect , Rect2 p_src_rect ) {
ERR_FAIL_COND ( p_texture . is_null ( ) ) ;
Rect2 final_rect ;
Rect2 final_src_rect ;
if ( ! p_texture - > get_rect_region ( p_dst_rect , p_src_rect , final_rect , final_src_rect ) ) {
return ;
}
if ( final_rect . size . x = = 0 | | final_rect . size . y = = 0 ) {
return ;
}
2022-09-18 20:08:31 +02:00
// 2D: 3D plane (axes match exactly when `axis == Vector3::AXIS_Z`):
// -X+ -X+
// - +
// Y +--------+ +--------+ +--------+ Y +--------+
// + | +--+ | | | (2) | | - | 0--1 |
// | |ab| | (1) | +--+ | (3) | 3--2 | | |ab| |
// | |cd| | --> | |ab| | --> | |cd| | <==> | |cd| |
// | +--+ | | |cd| | | |ab| | | 3--2 |
// | | | +--+ | | 0--1 | | |
// +--------+ +--------+ +--------+ +--------+
// (1) Y-wise shift `final_rect` within `p_dst_rect` so after inverting Y
// axis distances between top/bottom borders will be preserved (so for
// example AtlasTextures with vertical margins will look the same in 2D/3D).
final_rect . position . y = ( p_dst_rect . position . y + p_dst_rect . size . y ) - ( ( final_rect . position . y + final_rect . size . y ) - p_dst_rect . position . y ) ;
2022-09-18 20:03:03 +02:00
Color color = _get_color_accum ( ) ;
2022-09-29 11:53:28 +02:00
real_t px_size = get_pixel_size ( ) ;
2022-09-18 20:03:03 +02:00
2022-09-18 20:08:31 +02:00
// (2) Order vertices (0123) bottom-top in 2D / top-bottom in 3D.
2022-09-18 20:03:03 +02:00
Vector2 vertices [ 4 ] = {
2022-09-29 11:53:28 +02:00
( final_rect . position + Vector2 ( 0 , final_rect . size . y ) ) * px_size ,
( final_rect . position + final_rect . size ) * px_size ,
( final_rect . position + Vector2 ( final_rect . size . x , 0 ) ) * px_size ,
final_rect . position * px_size ,
2022-09-18 20:03:03 +02:00
} ;
Vector2 src_tsize = p_texture - > get_size ( ) ;
// Properly setup UVs for impostor textures (AtlasTexture).
Ref < AtlasTexture > atlas_tex = p_texture ;
if ( atlas_tex ! = nullptr ) {
src_tsize [ 0 ] = atlas_tex - > get_atlas ( ) - > get_width ( ) ;
src_tsize [ 1 ] = atlas_tex - > get_atlas ( ) - > get_height ( ) ;
}
2022-09-18 20:08:31 +02:00
// (3) Assign UVs (abcd) according to the vertices order (bottom-top in 2D / top-bottom in 3D).
2022-09-18 20:03:03 +02:00
Vector2 uvs [ 4 ] = {
final_src_rect . position / src_tsize ,
( final_src_rect . position + Vector2 ( final_src_rect . size . x , 0 ) ) / src_tsize ,
( final_src_rect . position + final_src_rect . size ) / src_tsize ,
( final_src_rect . position + Vector2 ( 0 , final_src_rect . size . y ) ) / src_tsize ,
} ;
if ( is_flipped_h ( ) ) {
SWAP ( uvs [ 0 ] , uvs [ 1 ] ) ;
SWAP ( uvs [ 2 ] , uvs [ 3 ] ) ;
}
if ( is_flipped_v ( ) ) {
SWAP ( uvs [ 0 ] , uvs [ 3 ] ) ;
SWAP ( uvs [ 1 ] , uvs [ 2 ] ) ;
}
Vector3 normal ;
2022-09-29 11:53:28 +02:00
int ax = get_axis ( ) ;
normal [ ax ] = 1.0 ;
2022-09-18 20:03:03 +02:00
Plane tangent ;
2022-09-29 11:53:28 +02:00
if ( ax = = Vector3 : : AXIS_X ) {
2022-09-18 20:03:03 +02:00
tangent = Plane ( 0 , 0 , - 1 , 1 ) ;
} else {
tangent = Plane ( 1 , 0 , 0 , 1 ) ;
}
2022-09-29 11:53:28 +02:00
int x_axis = ( ( ax + 1 ) % 3 ) ;
int y_axis = ( ( ax + 2 ) % 3 ) ;
2022-09-18 20:03:03 +02:00
2022-09-29 11:53:28 +02:00
if ( ax ! = Vector3 : : AXIS_Z ) {
2022-09-18 20:03:03 +02:00
SWAP ( x_axis , y_axis ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
//uvs[i] = Vector2(1.0,1.0)-uvs[i];
//SWAP(vertices[i].x,vertices[i].y);
2022-09-29 11:53:28 +02:00
if ( ax = = Vector3 : : AXIS_Y ) {
2022-09-18 20:03:03 +02:00
vertices [ i ] . y = - vertices [ i ] . y ;
2022-09-29 11:53:28 +02:00
} else if ( ax = = Vector3 : : AXIS_X ) {
2022-09-18 20:03:03 +02:00
vertices [ i ] . x = - vertices [ i ] . x ;
}
}
}
2022-09-29 11:53:28 +02:00
AABB aabb_new ;
2022-09-18 20:03:03 +02:00
// Everything except position and UV is compressed.
uint8_t * vertex_write_buffer = vertex_buffer . ptrw ( ) ;
uint8_t * attribute_write_buffer = attribute_buffer . ptrw ( ) ;
uint32_t v_normal ;
{
2022-12-15 00:41:43 +01:00
Vector2 res = normal . octahedron_encode ( ) ;
2022-09-18 20:03:03 +02:00
uint32_t value = 0 ;
value | = ( uint16_t ) CLAMP ( res . x * 65535 , 0 , 65535 ) ;
value | = ( uint16_t ) CLAMP ( res . y * 65535 , 0 , 65535 ) < < 16 ;
v_normal = value ;
}
uint32_t v_tangent ;
{
Plane t = tangent ;
Vector2 res = t . normal . octahedron_tangent_encode ( t . d ) ;
uint32_t value = 0 ;
value | = ( uint16_t ) CLAMP ( res . x * 65535 , 0 , 65535 ) ;
value | = ( uint16_t ) CLAMP ( res . y * 65535 , 0 , 65535 ) < < 16 ;
2023-10-12 05:34:52 +02:00
if ( value = = 4294901760 ) {
// (1, 1) and (0, 1) decode to the same value, but (0, 1) messes with our compression detection.
// So we sanitize here.
value = 4294967295 ;
}
2022-09-18 20:03:03 +02:00
v_tangent = value ;
}
uint8_t v_color [ 4 ] = {
uint8_t ( CLAMP ( color . r * 255.0 , 0.0 , 255.0 ) ) ,
uint8_t ( CLAMP ( color . g * 255.0 , 0.0 , 255.0 ) ) ,
uint8_t ( CLAMP ( color . b * 255.0 , 0.0 , 255.0 ) ) ,
uint8_t ( CLAMP ( color . a * 255.0 , 0.0 , 255.0 ) )
} ;
for ( int i = 0 ; i < 4 ; i + + ) {
Vector3 vtx ;
vtx [ x_axis ] = vertices [ i ] [ 0 ] ;
vtx [ y_axis ] = vertices [ i ] [ 1 ] ;
if ( i = = 0 ) {
2022-09-29 11:53:28 +02:00
aabb_new . position = vtx ;
aabb_new . size = Vector3 ( ) ;
2022-09-18 20:03:03 +02:00
} else {
2022-09-29 11:53:28 +02:00
aabb_new . expand_to ( vtx ) ;
2022-09-18 20:03:03 +02:00
}
float v_uv [ 2 ] = { ( float ) uvs [ i ] . x , ( float ) uvs [ i ] . y } ;
memcpy ( & attribute_write_buffer [ i * attrib_stride + mesh_surface_offsets [ RS : : ARRAY_TEX_UV ] ] , v_uv , 8 ) ;
float v_vertex [ 3 ] = { ( float ) vtx . x , ( float ) vtx . y , ( float ) vtx . z } ;
memcpy ( & vertex_write_buffer [ i * vertex_stride + mesh_surface_offsets [ RS : : ARRAY_VERTEX ] ] , & v_vertex , sizeof ( float ) * 3 ) ;
2023-08-29 21:04:32 +02:00
memcpy ( & vertex_write_buffer [ i * normal_tangent_stride + mesh_surface_offsets [ RS : : ARRAY_NORMAL ] ] , & v_normal , 4 ) ;
memcpy ( & vertex_write_buffer [ i * normal_tangent_stride + mesh_surface_offsets [ RS : : ARRAY_TANGENT ] ] , & v_tangent , 4 ) ;
2022-09-18 20:03:03 +02:00
memcpy ( & attribute_write_buffer [ i * attrib_stride + mesh_surface_offsets [ RS : : ARRAY_COLOR ] ] , v_color , 4 ) ;
}
2022-09-29 11:53:28 +02:00
RID mesh_new = get_mesh ( ) ;
RS : : get_singleton ( ) - > mesh_surface_update_vertex_region ( mesh_new , 0 , 0 , vertex_buffer ) ;
RS : : get_singleton ( ) - > mesh_surface_update_attribute_region ( mesh_new , 0 , 0 , attribute_buffer ) ;
2022-09-18 20:03:03 +02:00
2022-09-29 11:53:28 +02:00
RS : : get_singleton ( ) - > mesh_set_custom_aabb ( mesh_new , aabb_new ) ;
set_aabb ( aabb_new ) ;
2022-09-18 20:03:03 +02:00
2023-01-24 11:24:53 +01:00
RS : : get_singleton ( ) - > material_set_param ( get_material ( ) , " alpha_scissor_threshold " , alpha_scissor_threshold ) ;
RS : : get_singleton ( ) - > material_set_param ( get_material ( ) , " alpha_hash_scale " , alpha_hash_scale ) ;
2023-01-31 09:40:08 +01:00
RS : : get_singleton ( ) - > material_set_param ( get_material ( ) , " alpha_antialiasing_edge " , alpha_antialiasing_edge ) ;
2023-01-24 11:24:53 +01:00
BaseMaterial3D : : Transparency mat_transparency = BaseMaterial3D : : Transparency : : TRANSPARENCY_DISABLED ;
if ( get_draw_flag ( FLAG_TRANSPARENT ) ) {
if ( get_alpha_cut_mode ( ) = = ALPHA_CUT_DISCARD ) {
mat_transparency = BaseMaterial3D : : Transparency : : TRANSPARENCY_ALPHA_SCISSOR ;
} else if ( get_alpha_cut_mode ( ) = = ALPHA_CUT_OPAQUE_PREPASS ) {
mat_transparency = BaseMaterial3D : : Transparency : : TRANSPARENCY_ALPHA_DEPTH_PRE_PASS ;
} else if ( get_alpha_cut_mode ( ) = = ALPHA_CUT_HASH ) {
mat_transparency = BaseMaterial3D : : Transparency : : TRANSPARENCY_ALPHA_HASH ;
} else {
mat_transparency = BaseMaterial3D : : Transparency : : TRANSPARENCY_ALPHA ;
}
}
2022-09-18 20:03:03 +02:00
RID shader_rid ;
2023-01-31 09:40:08 +01:00
StandardMaterial3D : : get_material_for_2d ( get_draw_flag ( FLAG_SHADED ) , mat_transparency , get_draw_flag ( FLAG_DOUBLE_SIDED ) , get_billboard_mode ( ) = = StandardMaterial3D : : BILLBOARD_ENABLED , get_billboard_mode ( ) = = StandardMaterial3D : : BILLBOARD_FIXED_Y , false , get_draw_flag ( FLAG_DISABLE_DEPTH_TEST ) , get_draw_flag ( FLAG_FIXED_SIZE ) , get_texture_filter ( ) , alpha_antialiasing_mode , & shader_rid ) ;
2023-01-24 11:24:53 +01:00
2022-09-18 20:03:03 +02:00
if ( last_shader ! = shader_rid ) {
RS : : get_singleton ( ) - > material_set_shader ( get_material ( ) , shader_rid ) ;
last_shader = shader_rid ;
}
if ( last_texture ! = p_texture - > get_rid ( ) ) {
RS : : get_singleton ( ) - > material_set_param ( get_material ( ) , " texture_albedo " , p_texture - > get_rid ( ) ) ;
last_texture = p_texture - > get_rid ( ) ;
}
if ( get_alpha_cut_mode ( ) = = ALPHA_CUT_DISABLED ) {
RS : : get_singleton ( ) - > material_set_render_priority ( get_material ( ) , get_render_priority ( ) ) ;
RS : : get_singleton ( ) - > mesh_surface_set_material ( mesh , 0 , get_material ( ) ) ;
}
}
2014-05-29 15:56:39 +02:00
void SpriteBase3D : : set_centered ( bool p_center ) {
2023-11-24 15:33:23 +01:00
if ( centered = = p_center ) {
return ;
}
2017-03-05 16:44:50 +01:00
centered = p_center ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
}
bool SpriteBase3D : : is_centered ( ) const {
return centered ;
}
2017-03-05 16:44:50 +01:00
void SpriteBase3D : : set_offset ( const Point2 & p_offset ) {
2023-11-24 15:33:23 +01:00
if ( offset = = p_offset ) {
return ;
}
2017-03-05 16:44:50 +01:00
offset = p_offset ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
}
2020-05-14 14:29:06 +02:00
2014-05-29 15:56:39 +02:00
Point2 SpriteBase3D : : get_offset ( ) const {
return offset ;
}
void SpriteBase3D : : set_flip_h ( bool p_flip ) {
2023-11-24 15:33:23 +01:00
if ( hflip = = p_flip ) {
return ;
}
2017-03-05 16:44:50 +01:00
hflip = p_flip ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
}
2020-05-14 14:29:06 +02:00
2014-05-29 15:56:39 +02:00
bool SpriteBase3D : : is_flipped_h ( ) const {
return hflip ;
}
void SpriteBase3D : : set_flip_v ( bool p_flip ) {
2023-11-24 15:33:23 +01:00
if ( vflip = = p_flip ) {
return ;
}
2017-03-05 16:44:50 +01:00
vflip = p_flip ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
}
2020-05-14 14:29:06 +02:00
2014-05-29 15:56:39 +02:00
bool SpriteBase3D : : is_flipped_v ( ) const {
return vflip ;
}
2017-03-05 16:44:50 +01:00
void SpriteBase3D : : set_modulate ( const Color & p_color ) {
2023-11-24 15:33:23 +01:00
if ( modulate = = p_color ) {
return ;
}
2017-03-05 16:44:50 +01:00
modulate = p_color ;
2014-05-29 15:56:39 +02:00
_propagate_color_changed ( ) ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
}
2017-03-05 16:44:50 +01:00
Color SpriteBase3D : : get_modulate ( ) const {
2014-05-29 15:56:39 +02:00
return modulate ;
}
2022-04-30 10:41:50 +02:00
void SpriteBase3D : : set_render_priority ( int p_priority ) {
ERR_FAIL_COND ( p_priority < RS : : MATERIAL_RENDER_PRIORITY_MIN | | p_priority > RS : : MATERIAL_RENDER_PRIORITY_MAX ) ;
2023-11-24 15:33:23 +01:00
if ( render_priority = = p_priority ) {
return ;
}
2022-04-30 10:41:50 +02:00
render_priority = p_priority ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2022-04-30 10:41:50 +02:00
}
int SpriteBase3D : : get_render_priority ( ) const {
return render_priority ;
}
2021-01-30 01:55:54 +01:00
void SpriteBase3D : : set_pixel_size ( real_t p_amount ) {
2023-11-24 15:33:23 +01:00
if ( pixel_size = = p_amount ) {
return ;
}
2017-03-05 16:44:50 +01:00
pixel_size = p_amount ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
}
2020-05-14 14:29:06 +02:00
2021-01-30 01:55:54 +01:00
real_t SpriteBase3D : : get_pixel_size ( ) const {
2014-05-29 15:56:39 +02:00
return pixel_size ;
}
void SpriteBase3D : : set_axis ( Vector3 : : Axis p_axis ) {
2019-06-24 14:53:26 +02:00
ERR_FAIL_INDEX ( p_axis , 3 ) ;
2023-11-24 15:33:23 +01:00
if ( axis = = p_axis ) {
return ;
}
2017-03-05 16:44:50 +01:00
axis = p_axis ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
}
2020-05-14 14:29:06 +02:00
2014-05-29 15:56:39 +02:00
Vector3 : : Axis SpriteBase3D : : get_axis ( ) const {
return axis ;
}
void SpriteBase3D : : _im_update ( ) {
_draw ( ) ;
2017-03-05 16:44:50 +01:00
pending_update = false ;
2021-06-30 03:55:11 +02:00
//texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
2014-05-29 15:56:39 +02:00
}
2022-08-09 12:57:18 +02:00
void SpriteBase3D : : _queue_redraw ( ) {
// The 3D equivalent of CanvasItem.queue_redraw().
2020-05-14 16:41:43 +02:00
if ( pending_update ) {
2014-05-29 15:56:39 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2018-05-06 20:49:22 +02:00
triangle_mesh . unref ( ) ;
2021-06-23 16:49:50 +02:00
update_gizmos ( ) ;
2018-05-06 20:49:22 +02:00
2017-03-05 16:44:50 +01:00
pending_update = true ;
2023-07-12 14:38:01 +02:00
callable_mp ( this , & SpriteBase3D : : _im_update ) . call_deferred ( ) ;
2014-05-29 15:56:39 +02:00
}
2017-11-17 03:09:00 +01:00
AABB SpriteBase3D : : get_aabb ( ) const {
2014-05-29 15:56:39 +02:00
return aabb ;
}
2020-05-14 14:29:06 +02:00
2018-05-06 20:49:22 +02:00
Ref < TriangleMesh > SpriteBase3D : : generate_triangle_mesh ( ) const {
2020-05-14 16:41:43 +02:00
if ( triangle_mesh . is_valid ( ) ) {
2018-05-06 20:49:22 +02:00
return triangle_mesh ;
2020-05-14 16:41:43 +02:00
}
2018-05-06 20:49:22 +02:00
2020-02-17 22:06:54 +01:00
Vector < Vector3 > faces ;
2018-05-06 20:49:22 +02:00
faces . resize ( 6 ) ;
2020-02-17 22:06:54 +01:00
Vector3 * facesw = faces . ptrw ( ) ;
2018-05-06 20:49:22 +02:00
Rect2 final_rect = get_item_rect ( ) ;
2020-05-14 16:41:43 +02:00
if ( final_rect . size . x = = 0 | | final_rect . size . y = = 0 ) {
2018-05-06 20:49:22 +02:00
return Ref < TriangleMesh > ( ) ;
2020-05-14 16:41:43 +02:00
}
2018-05-06 20:49:22 +02:00
2022-09-29 11:53:28 +02:00
real_t px_size = get_pixel_size ( ) ;
2018-05-06 20:49:22 +02:00
Vector2 vertices [ 4 ] = {
2022-09-29 11:53:28 +02:00
( final_rect . position + Vector2 ( 0 , final_rect . size . y ) ) * px_size ,
( final_rect . position + final_rect . size ) * px_size ,
( final_rect . position + Vector2 ( final_rect . size . x , 0 ) ) * px_size ,
final_rect . position * px_size ,
2018-05-06 20:49:22 +02:00
} ;
int x_axis = ( ( axis + 1 ) % 3 ) ;
int y_axis = ( ( axis + 2 ) % 3 ) ;
if ( axis ! = Vector3 : : AXIS_Z ) {
SWAP ( x_axis , y_axis ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
if ( axis = = Vector3 : : AXIS_Y ) {
vertices [ i ] . y = - vertices [ i ] . y ;
} else if ( axis = = Vector3 : : AXIS_X ) {
vertices [ i ] . x = - vertices [ i ] . x ;
}
}
}
static const int indices [ 6 ] = {
0 , 1 , 2 ,
0 , 2 , 3
} ;
for ( int j = 0 ; j < 6 ; j + + ) {
int i = indices [ j ] ;
Vector3 vtx ;
vtx [ x_axis ] = vertices [ i ] [ 0 ] ;
vtx [ y_axis ] = vertices [ i ] [ 1 ] ;
facesw [ j ] = vtx ;
}
triangle_mesh = Ref < TriangleMesh > ( memnew ( TriangleMesh ) ) ;
triangle_mesh - > create ( faces ) ;
return triangle_mesh ;
}
2017-03-05 16:44:50 +01:00
void SpriteBase3D : : set_draw_flag ( DrawFlags p_flag , bool p_enable ) {
ERR_FAIL_INDEX ( p_flag , FLAG_MAX ) ;
2023-11-24 15:33:23 +01:00
if ( flags [ p_flag ] = = p_enable ) {
return ;
}
2017-03-05 16:44:50 +01:00
flags [ p_flag ] = p_enable ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
}
2017-03-05 16:44:50 +01:00
bool SpriteBase3D : : get_draw_flag ( DrawFlags p_flag ) const {
ERR_FAIL_INDEX_V ( p_flag , FLAG_MAX , false ) ;
2014-05-29 15:56:39 +02:00
return flags [ p_flag ] ;
}
2017-03-05 16:44:50 +01:00
void SpriteBase3D : : set_alpha_cut_mode ( AlphaCutMode p_mode ) {
2023-01-24 11:24:53 +01:00
ERR_FAIL_INDEX ( p_mode , ALPHA_CUT_MAX ) ;
2023-11-24 15:33:23 +01:00
if ( alpha_cut = = p_mode ) {
return ;
}
2017-03-05 16:44:50 +01:00
alpha_cut = p_mode ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
}
2017-03-05 16:44:50 +01:00
SpriteBase3D : : AlphaCutMode SpriteBase3D : : get_alpha_cut_mode ( ) const {
2014-05-29 15:56:39 +02:00
return alpha_cut ;
}
2023-01-24 11:24:53 +01:00
void SpriteBase3D : : set_alpha_hash_scale ( float p_hash_scale ) {
2023-11-24 15:33:23 +01:00
if ( alpha_hash_scale = = p_hash_scale ) {
return ;
2023-01-24 11:24:53 +01:00
}
2023-11-24 15:33:23 +01:00
alpha_hash_scale = p_hash_scale ;
_queue_redraw ( ) ;
2023-01-24 11:24:53 +01:00
}
float SpriteBase3D : : get_alpha_hash_scale ( ) const {
return alpha_hash_scale ;
}
void SpriteBase3D : : set_alpha_scissor_threshold ( float p_threshold ) {
2023-11-24 15:33:23 +01:00
if ( alpha_scissor_threshold = = p_threshold ) {
return ;
2023-01-24 11:24:53 +01:00
}
2023-11-24 15:33:23 +01:00
alpha_scissor_threshold = p_threshold ;
_queue_redraw ( ) ;
2023-01-24 11:24:53 +01:00
}
float SpriteBase3D : : get_alpha_scissor_threshold ( ) const {
return alpha_scissor_threshold ;
}
2023-01-31 09:40:08 +01:00
void SpriteBase3D : : set_alpha_antialiasing ( BaseMaterial3D : : AlphaAntiAliasing p_alpha_aa ) {
2023-11-24 15:33:23 +01:00
if ( alpha_antialiasing_mode = = p_alpha_aa ) {
return ;
2023-01-31 09:40:08 +01:00
}
2023-11-24 15:33:23 +01:00
alpha_antialiasing_mode = p_alpha_aa ;
_queue_redraw ( ) ;
2023-01-31 09:40:08 +01:00
}
BaseMaterial3D : : AlphaAntiAliasing SpriteBase3D : : get_alpha_antialiasing ( ) const {
return alpha_antialiasing_mode ;
}
void SpriteBase3D : : set_alpha_antialiasing_edge ( float p_edge ) {
2023-11-24 15:33:23 +01:00
if ( alpha_antialiasing_edge = = p_edge ) {
return ;
2023-01-31 09:40:08 +01:00
}
2023-11-24 15:33:23 +01:00
alpha_antialiasing_edge = p_edge ;
_queue_redraw ( ) ;
2023-01-31 09:40:08 +01:00
}
float SpriteBase3D : : get_alpha_antialiasing_edge ( ) const {
return alpha_antialiasing_edge ;
}
2019-09-15 06:01:52 +02:00
void SpriteBase3D : : set_billboard_mode ( StandardMaterial3D : : BillboardMode p_mode ) {
2022-08-09 12:57:18 +02:00
ERR_FAIL_INDEX ( p_mode , 3 ) ; // Cannot use BILLBOARD_PARTICLES.
2023-11-24 15:33:23 +01:00
if ( billboard_mode = = p_mode ) {
return ;
}
2019-07-17 01:04:36 +02:00
billboard_mode = p_mode ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2019-07-17 01:04:36 +02:00
}
2019-09-15 06:01:52 +02:00
StandardMaterial3D : : BillboardMode SpriteBase3D : : get_billboard_mode ( ) const {
2019-07-17 01:04:36 +02:00
return billboard_mode ;
}
2022-04-19 12:27:18 +02:00
void SpriteBase3D : : set_texture_filter ( StandardMaterial3D : : TextureFilter p_filter ) {
2023-11-24 15:33:23 +01:00
if ( texture_filter = = p_filter ) {
return ;
2022-04-19 12:27:18 +02:00
}
2023-11-24 15:33:23 +01:00
texture_filter = p_filter ;
_queue_redraw ( ) ;
2022-04-19 12:27:18 +02:00
}
StandardMaterial3D : : TextureFilter SpriteBase3D : : get_texture_filter ( ) const {
return texture_filter ;
}
2014-05-29 15:56:39 +02:00
void SpriteBase3D : : _bind_methods ( ) {
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_centered " , " centered " ) , & SpriteBase3D : : set_centered ) ;
ClassDB : : bind_method ( D_METHOD ( " is_centered " ) , & SpriteBase3D : : is_centered ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_offset " , " offset " ) , & SpriteBase3D : : set_offset ) ;
ClassDB : : bind_method ( D_METHOD ( " get_offset " ) , & SpriteBase3D : : get_offset ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_flip_h " , " flip_h " ) , & SpriteBase3D : : set_flip_h ) ;
ClassDB : : bind_method ( D_METHOD ( " is_flipped_h " ) , & SpriteBase3D : : is_flipped_h ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_flip_v " , " flip_v " ) , & SpriteBase3D : : set_flip_v ) ;
ClassDB : : bind_method ( D_METHOD ( " is_flipped_v " ) , & SpriteBase3D : : is_flipped_v ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_modulate " , " modulate " ) , & SpriteBase3D : : set_modulate ) ;
ClassDB : : bind_method ( D_METHOD ( " get_modulate " ) , & SpriteBase3D : : get_modulate ) ;
2014-05-29 15:56:39 +02:00
2022-04-30 10:41:50 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_render_priority " , " priority " ) , & SpriteBase3D : : set_render_priority ) ;
ClassDB : : bind_method ( D_METHOD ( " get_render_priority " ) , & SpriteBase3D : : get_render_priority ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_pixel_size " , " pixel_size " ) , & SpriteBase3D : : set_pixel_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_pixel_size " ) , & SpriteBase3D : : get_pixel_size ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_axis " , " axis " ) , & SpriteBase3D : : set_axis ) ;
ClassDB : : bind_method ( D_METHOD ( " get_axis " ) , & SpriteBase3D : : get_axis ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_draw_flag " , " flag " , " enabled " ) , & SpriteBase3D : : set_draw_flag ) ;
ClassDB : : bind_method ( D_METHOD ( " get_draw_flag " , " flag " ) , & SpriteBase3D : : get_draw_flag ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_alpha_cut_mode " , " mode " ) , & SpriteBase3D : : set_alpha_cut_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_alpha_cut_mode " ) , & SpriteBase3D : : get_alpha_cut_mode ) ;
2014-05-29 15:56:39 +02:00
2023-01-24 11:24:53 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_alpha_scissor_threshold " , " threshold " ) , & SpriteBase3D : : set_alpha_scissor_threshold ) ;
ClassDB : : bind_method ( D_METHOD ( " get_alpha_scissor_threshold " ) , & SpriteBase3D : : get_alpha_scissor_threshold ) ;
ClassDB : : bind_method ( D_METHOD ( " set_alpha_hash_scale " , " threshold " ) , & SpriteBase3D : : set_alpha_hash_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " get_alpha_hash_scale " ) , & SpriteBase3D : : get_alpha_hash_scale ) ;
2023-01-31 09:40:08 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_alpha_antialiasing " , " alpha_aa " ) , & SpriteBase3D : : set_alpha_antialiasing ) ;
ClassDB : : bind_method ( D_METHOD ( " get_alpha_antialiasing " ) , & SpriteBase3D : : get_alpha_antialiasing ) ;
ClassDB : : bind_method ( D_METHOD ( " set_alpha_antialiasing_edge " , " edge " ) , & SpriteBase3D : : set_alpha_antialiasing_edge ) ;
ClassDB : : bind_method ( D_METHOD ( " get_alpha_antialiasing_edge " ) , & SpriteBase3D : : get_alpha_antialiasing_edge ) ;
2019-07-17 01:04:36 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_billboard_mode " , " mode " ) , & SpriteBase3D : : set_billboard_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_billboard_mode " ) , & SpriteBase3D : : get_billboard_mode ) ;
2022-04-19 12:27:18 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_texture_filter " , " mode " ) , & SpriteBase3D : : set_texture_filter ) ;
ClassDB : : bind_method ( D_METHOD ( " get_texture_filter " ) , & SpriteBase3D : : get_texture_filter ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_item_rect " ) , & SpriteBase3D : : get_item_rect ) ;
2018-05-06 20:49:22 +02:00
ClassDB : : bind_method ( D_METHOD ( " generate_triangle_mesh " ) , & SpriteBase3D : : generate_triangle_mesh ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " centered " ) , " set_centered " , " is_centered " ) ;
2022-05-20 07:24:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " offset " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_offset " , " get_offset " ) ;
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " flip_h " ) , " set_flip_h " , " is_flipped_h " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " flip_v " ) , " set_flip_v " , " is_flipped_v " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : COLOR , " modulate " ) , " set_modulate " , " get_modulate " ) ;
2022-05-20 07:24:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " pixel_size " , PROPERTY_HINT_RANGE , " 0.0001,128,0.0001,suffix:m " ) , " set_pixel_size " , " get_pixel_size " ) ;
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " axis " , PROPERTY_HINT_ENUM , " X-Axis,Y-Axis,Z-Axis " ) , " set_axis " , " get_axis " ) ;
ADD_GROUP ( " Flags " , " " ) ;
2019-07-17 01:04:36 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " billboard " , PROPERTY_HINT_ENUM , " Disabled,Enabled,Y-Billboard " ) , " set_billboard_mode " , " get_billboard_mode " ) ;
2017-03-05 16:44:50 +01:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " transparent " ) , " set_draw_flag " , " get_draw_flag " , FLAG_TRANSPARENT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " shaded " ) , " set_draw_flag " , " get_draw_flag " , FLAG_SHADED ) ;
2017-04-17 03:32:51 +02:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " double_sided " ) , " set_draw_flag " , " get_draw_flag " , FLAG_DOUBLE_SIDED ) ;
2022-04-19 12:27:18 +02:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " no_depth_test " ) , " set_draw_flag " , " get_draw_flag " , FLAG_DISABLE_DEPTH_TEST ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " fixed_size " ) , " set_draw_flag " , " get_draw_flag " , FLAG_FIXED_SIZE ) ;
2023-01-24 11:24:53 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " alpha_cut " , PROPERTY_HINT_ENUM , " Disabled,Discard,Opaque Pre-Pass,Alpha Hash " ) , " set_alpha_cut_mode " , " get_alpha_cut_mode " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " alpha_scissor_threshold " , PROPERTY_HINT_RANGE , " 0,1,0.001 " ) , " set_alpha_scissor_threshold " , " get_alpha_scissor_threshold " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " alpha_hash_scale " , PROPERTY_HINT_RANGE , " 0,2,0.01 " ) , " set_alpha_hash_scale " , " get_alpha_hash_scale " ) ;
2023-01-31 09:40:08 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " alpha_antialiasing_mode " , PROPERTY_HINT_ENUM , " Disabled,Alpha Edge Blend,Alpha Edge Clip " ) , " set_alpha_antialiasing " , " get_alpha_antialiasing " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " alpha_antialiasing_edge " , PROPERTY_HINT_RANGE , " 0,1,0.01 " ) , " set_alpha_antialiasing_edge " , " get_alpha_antialiasing_edge " ) ;
2022-04-19 12:27:18 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " texture_filter " , PROPERTY_HINT_ENUM , " Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic " ) , " set_texture_filter " , " get_texture_filter " ) ;
2022-04-30 10:41:50 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " render_priority " , PROPERTY_HINT_RANGE , itos ( RS : : MATERIAL_RENDER_PRIORITY_MIN ) + " , " + itos ( RS : : MATERIAL_RENDER_PRIORITY_MAX ) + " ,1 " ) , " set_render_priority " , " get_render_priority " ) ;
2014-12-07 06:04:20 +01:00
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( FLAG_TRANSPARENT ) ;
BIND_ENUM_CONSTANT ( FLAG_SHADED ) ;
BIND_ENUM_CONSTANT ( FLAG_DOUBLE_SIDED ) ;
2022-04-19 12:27:18 +02:00
BIND_ENUM_CONSTANT ( FLAG_DISABLE_DEPTH_TEST ) ;
BIND_ENUM_CONSTANT ( FLAG_FIXED_SIZE ) ;
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( FLAG_MAX ) ;
BIND_ENUM_CONSTANT ( ALPHA_CUT_DISABLED ) ;
BIND_ENUM_CONSTANT ( ALPHA_CUT_DISCARD ) ;
BIND_ENUM_CONSTANT ( ALPHA_CUT_OPAQUE_PREPASS ) ;
2023-01-24 11:24:53 +01:00
BIND_ENUM_CONSTANT ( ALPHA_CUT_HASH ) ;
2014-05-29 15:56:39 +02:00
}
SpriteBase3D : : SpriteBase3D ( ) {
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < FLAG_MAX ; i + + ) {
2017-04-17 03:32:51 +02:00
flags [ i ] = i = = FLAG_TRANSPARENT | | i = = FLAG_DOUBLE_SIDED ;
2020-05-14 16:41:43 +02:00
}
2017-03-05 16:44:50 +01:00
2021-06-30 03:55:11 +02:00
material = RenderingServer : : get_singleton ( ) - > material_create ( ) ;
2022-08-09 12:57:18 +02:00
// Set defaults for material, names need to match up those in StandardMaterial3D.
2021-06-30 03:55:11 +02:00
RS : : get_singleton ( ) - > material_set_param ( material , " albedo " , Color ( 1 , 1 , 1 , 1 ) ) ;
RS : : get_singleton ( ) - > material_set_param ( material , " specular " , 0.5 ) ;
RS : : get_singleton ( ) - > material_set_param ( material , " metallic " , 0.0 ) ;
RS : : get_singleton ( ) - > material_set_param ( material , " roughness " , 1.0 ) ;
RS : : get_singleton ( ) - > material_set_param ( material , " uv1_offset " , Vector3 ( 0 , 0 , 0 ) ) ;
RS : : get_singleton ( ) - > material_set_param ( material , " uv1_scale " , Vector3 ( 1 , 1 , 1 ) ) ;
RS : : get_singleton ( ) - > material_set_param ( material , " uv2_offset " , Vector3 ( 0 , 0 , 0 ) ) ;
RS : : get_singleton ( ) - > material_set_param ( material , " uv2_scale " , Vector3 ( 1 , 1 , 1 ) ) ;
mesh = RenderingServer : : get_singleton ( ) - > mesh_create ( ) ;
PackedVector3Array mesh_vertices ;
PackedVector3Array mesh_normals ;
PackedFloat32Array mesh_tangents ;
PackedColorArray mesh_colors ;
PackedVector2Array mesh_uvs ;
PackedInt32Array indices ;
mesh_vertices . resize ( 4 ) ;
mesh_normals . resize ( 4 ) ;
mesh_tangents . resize ( 16 ) ;
mesh_colors . resize ( 4 ) ;
mesh_uvs . resize ( 4 ) ;
2022-08-09 12:57:18 +02:00
// Create basic mesh and store format information.
2021-06-30 03:55:11 +02:00
for ( int i = 0 ; i < 4 ; i + + ) {
2023-07-01 15:46:52 +02:00
mesh_normals . write [ i ] = Vector3 ( 0.0 , 0.0 , 1.0 ) ;
mesh_tangents . write [ i * 4 + 0 ] = 1.0 ;
2021-06-30 03:55:11 +02:00
mesh_tangents . write [ i * 4 + 1 ] = 0.0 ;
mesh_tangents . write [ i * 4 + 2 ] = 0.0 ;
2023-07-01 15:46:52 +02:00
mesh_tangents . write [ i * 4 + 3 ] = 1.0 ;
2021-06-30 03:55:11 +02:00
mesh_colors . write [ i ] = Color ( 1.0 , 1.0 , 1.0 , 1.0 ) ;
mesh_uvs . write [ i ] = Vector2 ( 0.0 , 0.0 ) ;
mesh_vertices . write [ i ] = Vector3 ( 0.0 , 0.0 , 0.0 ) ;
}
indices . resize ( 6 ) ;
indices . write [ 0 ] = 0 ;
indices . write [ 1 ] = 1 ;
indices . write [ 2 ] = 2 ;
indices . write [ 3 ] = 0 ;
indices . write [ 4 ] = 2 ;
indices . write [ 5 ] = 3 ;
Array mesh_array ;
mesh_array . resize ( RS : : ARRAY_MAX ) ;
mesh_array [ RS : : ARRAY_VERTEX ] = mesh_vertices ;
mesh_array [ RS : : ARRAY_NORMAL ] = mesh_normals ;
mesh_array [ RS : : ARRAY_TANGENT ] = mesh_tangents ;
mesh_array [ RS : : ARRAY_COLOR ] = mesh_colors ;
mesh_array [ RS : : ARRAY_TEX_UV ] = mesh_uvs ;
mesh_array [ RS : : ARRAY_INDEX ] = indices ;
RS : : SurfaceData sd ;
RS : : get_singleton ( ) - > mesh_create_surface_data_from_arrays ( & sd , RS : : PRIMITIVE_TRIANGLES , mesh_array ) ;
mesh_surface_format = sd . format ;
vertex_buffer = sd . vertex_data ;
attribute_buffer = sd . attribute_data ;
sd . material = material ;
2023-08-29 21:04:32 +02:00
RS : : get_singleton ( ) - > mesh_surface_make_offsets_from_format ( sd . format , sd . vertex_count , sd . index_count , mesh_surface_offsets , vertex_stride , normal_tangent_stride , attrib_stride , skin_stride ) ;
2021-06-30 03:55:11 +02:00
RS : : get_singleton ( ) - > mesh_add_surface ( mesh , sd ) ;
set_base ( mesh ) ;
2014-05-29 15:56:39 +02:00
}
SpriteBase3D : : ~ SpriteBase3D ( ) {
2022-12-12 18:42:37 +01:00
ERR_FAIL_NULL ( RenderingServer : : get_singleton ( ) ) ;
2021-06-30 03:55:11 +02:00
RenderingServer : : get_singleton ( ) - > free ( mesh ) ;
RenderingServer : : get_singleton ( ) - > free ( material ) ;
2014-05-29 15:56:39 +02:00
}
///////////////////////////////////////////
void Sprite3D : : _draw ( ) {
2021-06-30 03:55:11 +02:00
if ( get_base ( ) ! = get_mesh ( ) ) {
set_base ( get_mesh ( ) ) ;
}
2022-08-31 16:15:24 +02:00
if ( texture . is_null ( ) ) {
2021-06-30 03:55:11 +02:00
set_base ( RID ( ) ) ;
2019-02-04 23:19:00 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
Vector2 tsize = texture - > get_size ( ) ;
2020-05-14 16:41:43 +02:00
if ( tsize . x = = 0 | | tsize . y = = 0 ) {
2014-05-29 15:56:39 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2019-02-04 23:19:00 +01:00
Rect2 base_rect ;
2021-06-30 03:55:11 +02:00
if ( region ) {
2019-02-04 23:19:00 +01:00
base_rect = region_rect ;
2020-05-14 16:41:43 +02:00
} else {
2019-02-04 23:19:00 +01:00
base_rect = Rect2 ( 0 , 0 , texture - > get_width ( ) , texture - > get_height ( ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2019-02-04 23:19:00 +01:00
Size2 frame_size = base_rect . size / Size2 ( hframes , vframes ) ;
2022-09-18 20:03:03 +02:00
Point2 frame_offset = Point2 ( frame % hframes , frame / hframes ) * frame_size ;
2014-05-29 15:56:39 +02:00
2022-09-18 20:03:03 +02:00
Point2 dst_offset = get_offset ( ) ;
2020-05-14 16:41:43 +02:00
if ( is_centered ( ) ) {
2022-09-18 20:03:03 +02:00
dst_offset - = frame_size / 2.0f ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2019-02-04 23:19:00 +01:00
Rect2 src_rect ( base_rect . position + frame_offset , frame_size ) ;
2022-09-18 20:03:03 +02:00
Rect2 dst_rect ( dst_offset , frame_size ) ;
2022-08-20 19:01:46 +02:00
2022-09-18 20:03:03 +02:00
draw_texture_rect ( texture , dst_rect , src_rect ) ;
2020-02-27 22:49:16 +01:00
}
2019-06-11 20:43:37 +02:00
void Sprite3D : : set_texture ( const Ref < Texture2D > & p_texture ) {
2020-05-14 16:41:43 +02:00
if ( p_texture = = texture ) {
2014-05-29 15:56:39 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
if ( texture . is_valid ( ) ) {
2024-05-13 16:56:03 +02:00
texture - > disconnect ( CoreStringName ( changed ) , callable_mp ( ( SpriteBase3D * ) this , & Sprite3D : : _queue_redraw ) ) ;
2014-05-29 15:56:39 +02:00
}
2017-03-05 16:44:50 +01:00
texture = p_texture ;
2014-05-29 15:56:39 +02:00
if ( texture . is_valid ( ) ) {
2024-05-13 16:56:03 +02:00
texture - > connect ( CoreStringName ( changed ) , callable_mp ( ( SpriteBase3D * ) this , & Sprite3D : : _queue_redraw ) ) ;
2014-05-29 15:56:39 +02:00
}
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( texture_changed ) ) ;
2014-05-29 15:56:39 +02:00
}
2019-06-11 20:43:37 +02:00
Ref < Texture2D > Sprite3D : : get_texture ( ) const {
2014-05-29 15:56:39 +02:00
return texture ;
}
2021-06-30 03:55:11 +02:00
void Sprite3D : : set_region_enabled ( bool p_region ) {
if ( p_region = = region ) {
2014-05-29 15:56:39 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2021-06-30 03:55:11 +02:00
region = p_region ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2022-10-23 17:35:29 +02:00
notify_property_list_changed ( ) ;
2014-05-29 15:56:39 +02:00
}
2021-03-14 14:43:43 +01:00
bool Sprite3D : : is_region_enabled ( ) const {
2021-06-30 03:55:11 +02:00
return region ;
2014-05-29 15:56:39 +02:00
}
2017-03-05 16:44:50 +01:00
void Sprite3D : : set_region_rect ( const Rect2 & p_region_rect ) {
2023-11-24 15:33:23 +01:00
if ( region_rect = = p_region_rect ) {
return ;
}
2017-03-05 16:44:50 +01:00
region_rect = p_region_rect ;
2023-11-24 15:33:23 +01:00
if ( region ) {
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2014-05-29 15:56:39 +02:00
}
}
Rect2 Sprite3D : : get_region_rect ( ) const {
return region_rect ;
}
void Sprite3D : : set_frame ( int p_frame ) {
2019-07-20 08:09:57 +02:00
ERR_FAIL_INDEX ( p_frame , int64_t ( vframes ) * hframes ) ;
2014-05-29 15:56:39 +02:00
2023-11-24 15:33:23 +01:00
if ( frame = = p_frame ) {
return ;
}
2014-05-29 15:56:39 +02:00
2023-11-24 15:33:23 +01:00
frame = p_frame ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( frame_changed ) ) ;
2014-05-29 15:56:39 +02:00
}
int Sprite3D : : get_frame ( ) const {
return frame ;
}
2021-05-23 18:46:39 +02:00
void Sprite3D : : set_frame_coords ( const Vector2i & p_coord ) {
ERR_FAIL_INDEX ( p_coord . x , hframes ) ;
ERR_FAIL_INDEX ( p_coord . y , vframes ) ;
2019-01-25 19:21:23 +01:00
2021-05-23 18:46:39 +02:00
set_frame ( p_coord . y * hframes + p_coord . x ) ;
2019-01-25 19:21:23 +01:00
}
2021-05-23 18:46:39 +02:00
Vector2i Sprite3D : : get_frame_coords ( ) const {
return Vector2i ( frame % hframes , frame / hframes ) ;
2019-01-25 19:21:23 +01:00
}
2014-05-29 15:56:39 +02:00
void Sprite3D : : set_vframes ( int p_amount ) {
2023-11-24 17:47:55 +01:00
ERR_FAIL_COND_MSG ( p_amount < 1 , " Amount of vframes cannot be smaller than 1. " ) ;
2023-11-24 15:33:23 +01:00
if ( vframes = = p_amount ) {
return ;
}
2017-03-05 16:44:50 +01:00
vframes = p_amount ;
2023-11-24 17:47:55 +01:00
if ( frame > = vframes * hframes ) {
frame = 0 ;
}
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2021-02-10 21:18:45 +01:00
notify_property_list_changed ( ) ;
2014-05-29 15:56:39 +02:00
}
2020-05-14 14:29:06 +02:00
2014-05-29 15:56:39 +02:00
int Sprite3D : : get_vframes ( ) const {
return vframes ;
}
void Sprite3D : : set_hframes ( int p_amount ) {
2023-11-24 17:47:55 +01:00
ERR_FAIL_COND_MSG ( p_amount < 1 , " Amount of hframes cannot be smaller than 1. " ) ;
2023-11-24 15:33:23 +01:00
if ( hframes = = p_amount ) {
return ;
}
2023-11-24 17:47:55 +01:00
if ( vframes > 1 ) {
// Adjust the frame to fit new sheet dimensions.
int original_column = frame % hframes ;
if ( original_column > = p_amount ) {
// Frame's column was dropped, reset.
frame = 0 ;
} else {
int original_row = frame / hframes ;
frame = original_row * p_amount + original_column ;
}
}
2017-03-05 16:44:50 +01:00
hframes = p_amount ;
2023-11-24 17:47:55 +01:00
if ( frame > = vframes * hframes ) {
frame = 0 ;
}
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2021-02-10 21:18:45 +01:00
notify_property_list_changed ( ) ;
2014-05-29 15:56:39 +02:00
}
2020-05-14 14:29:06 +02:00
2014-05-29 15:56:39 +02:00
int Sprite3D : : get_hframes ( ) const {
return hframes ;
}
Rect2 Sprite3D : : get_item_rect ( ) const {
2020-05-14 16:41:43 +02:00
if ( texture . is_null ( ) ) {
2017-03-05 16:44:50 +01:00
return Rect2 ( 0 , 0 , 1 , 1 ) ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2021-09-25 12:18:18 +02:00
Size2 s ;
2014-05-29 15:56:39 +02:00
2021-06-30 03:55:11 +02:00
if ( region ) {
2017-03-05 16:44:50 +01:00
s = region_rect . size ;
2014-05-29 15:56:39 +02:00
} else {
s = texture - > get_size ( ) ;
2017-03-05 16:44:50 +01:00
s = s / Point2 ( hframes , vframes ) ;
2014-05-29 15:56:39 +02:00
}
2018-10-26 11:50:21 +02:00
Point2 ofs = get_offset ( ) ;
2020-05-14 16:41:43 +02:00
if ( is_centered ( ) ) {
2017-03-05 16:44:50 +01:00
ofs - = s / 2 ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2020-05-14 16:41:43 +02:00
if ( s = = Size2 ( 0 , 0 ) ) {
2017-03-05 16:44:50 +01:00
s = Size2 ( 1 , 1 ) ;
2020-05-14 16:41:43 +02:00
}
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
return Rect2 ( ofs , s ) ;
2014-05-29 15:56:39 +02:00
}
2022-08-12 22:57:11 +02:00
void Sprite3D : : _validate_property ( PropertyInfo & p_property ) const {
if ( p_property . name = = " frame " ) {
p_property . hint = PROPERTY_HINT_RANGE ;
p_property . hint_string = " 0, " + itos ( vframes * hframes - 1 ) + " ,1 " ;
p_property . usage | = PROPERTY_USAGE_KEYING_INCREMENTS ;
2016-07-07 04:46:04 +02:00
}
2019-10-22 19:01:23 +02:00
2022-08-12 22:57:11 +02:00
if ( p_property . name = = " frame_coords " ) {
p_property . usage | = PROPERTY_USAGE_KEYING_INCREMENTS ;
2019-10-22 19:01:23 +02:00
}
2022-10-23 17:35:29 +02:00
if ( ! region & & ( p_property . name = = " region_rect " ) ) {
p_property . usage = PROPERTY_USAGE_NO_EDITOR ;
}
2016-07-07 04:46:04 +02:00
}
2014-05-29 15:56:39 +02:00
void Sprite3D : : _bind_methods ( ) {
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_texture " , " texture " ) , & Sprite3D : : set_texture ) ;
ClassDB : : bind_method ( D_METHOD ( " get_texture " ) , & Sprite3D : : get_texture ) ;
2014-05-29 15:56:39 +02:00
2021-03-14 14:43:43 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_region_enabled " , " enabled " ) , & Sprite3D : : set_region_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_region_enabled " ) , & Sprite3D : : is_region_enabled ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_region_rect " , " rect " ) , & Sprite3D : : set_region_rect ) ;
ClassDB : : bind_method ( D_METHOD ( " get_region_rect " ) , & Sprite3D : : get_region_rect ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_frame " , " frame " ) , & Sprite3D : : set_frame ) ;
ClassDB : : bind_method ( D_METHOD ( " get_frame " ) , & Sprite3D : : get_frame ) ;
2014-05-29 15:56:39 +02:00
2019-01-25 19:21:23 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_frame_coords " , " coords " ) , & Sprite3D : : set_frame_coords ) ;
ClassDB : : bind_method ( D_METHOD ( " get_frame_coords " ) , & Sprite3D : : get_frame_coords ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_vframes " , " vframes " ) , & Sprite3D : : set_vframes ) ;
ClassDB : : bind_method ( D_METHOD ( " get_vframes " ) , & Sprite3D : : get_vframes ) ;
2014-05-29 15:56:39 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_hframes " , " hframes " ) , & Sprite3D : : set_hframes ) ;
ClassDB : : bind_method ( D_METHOD ( " get_hframes " ) , & Sprite3D : : get_hframes ) ;
2014-05-29 15:56:39 +02:00
2023-10-28 15:52:11 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " texture " , PROPERTY_HINT_RESOURCE_TYPE , " Texture2D " ) , " set_texture " , " get_texture " ) ;
2017-06-25 23:57:28 +02:00
ADD_GROUP ( " Animation " , " " ) ;
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " hframes " , PROPERTY_HINT_RANGE , " 1,16384,1 " ) , " set_hframes " , " get_hframes " ) ;
2020-08-22 01:56:14 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " vframes " , PROPERTY_HINT_RANGE , " 1,16384,1 " ) , " set_vframes " , " get_vframes " ) ;
2019-07-25 09:11:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " frame " ) , " set_frame " , " get_frame " ) ;
2024-07-05 22:18:23 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2I , " frame_coords " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_EDITOR ) , " set_frame_coords " , " get_frame_coords " ) ;
2017-06-25 23:57:28 +02:00
ADD_GROUP ( " Region " , " region_ " ) ;
2021-03-14 14:43:43 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " region_enabled " ) , " set_region_enabled " , " is_region_enabled " ) ;
2022-05-20 07:24:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : RECT2 , " region_rect " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_region_rect " , " get_region_rect " ) ;
2014-05-29 15:56:39 +02:00
2014-12-07 06:04:20 +01:00
ADD_SIGNAL ( MethodInfo ( " frame_changed " ) ) ;
2021-10-01 09:14:05 +02:00
ADD_SIGNAL ( MethodInfo ( " texture_changed " ) ) ;
2014-05-29 15:56:39 +02:00
}
Sprite3D : : Sprite3D ( ) {
}
////////////////////////////////////////
2016-06-08 23:03:06 +02:00
void AnimatedSprite3D : : _draw ( ) {
2021-06-30 03:55:11 +02:00
if ( get_base ( ) ! = get_mesh ( ) ) {
set_base ( get_mesh ( ) ) ;
}
2016-06-08 23:03:06 +02:00
2022-08-31 16:15:24 +02:00
if ( frames . is_null ( ) | | ! frames - > has_animation ( animation ) ) {
2016-06-08 23:03:06 +02:00
return ;
}
2022-11-26 15:00:38 +01:00
Ref < Texture2D > texture = frames - > get_frame_texture ( animation , frame ) ;
2022-08-09 12:57:18 +02:00
if ( texture . is_null ( ) ) {
2021-06-30 03:55:11 +02:00
set_base ( RID ( ) ) ;
2022-08-09 12:57:18 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2021-09-25 12:18:18 +02:00
Size2 tsize = texture - > get_size ( ) ;
2020-05-14 16:41:43 +02:00
if ( tsize . x = = 0 | | tsize . y = = 0 ) {
2016-06-08 23:03:06 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-06-08 23:03:06 +02:00
2018-10-26 11:50:21 +02:00
Rect2 src_rect ;
2021-09-25 12:18:18 +02:00
src_rect . size = tsize ;
2016-06-08 23:03:06 +02:00
2018-10-26 11:50:21 +02:00
Point2 ofs = get_offset ( ) ;
2020-05-14 16:41:43 +02:00
if ( is_centered ( ) ) {
2021-09-25 12:18:18 +02:00
ofs - = tsize / 2 ;
2020-05-14 16:41:43 +02:00
}
2016-06-08 23:03:06 +02:00
2021-09-25 12:18:18 +02:00
Rect2 dst_rect ( ofs , tsize ) ;
2016-06-08 23:03:06 +02:00
2022-09-18 20:03:03 +02:00
draw_texture_rect ( texture , dst_rect , src_rect ) ;
2016-06-08 23:03:06 +02:00
}
2022-08-12 22:57:11 +02:00
void AnimatedSprite3D : : _validate_property ( PropertyInfo & p_property ) const {
2020-05-14 16:41:43 +02:00
if ( ! frames . is_valid ( ) ) {
2016-06-08 23:03:06 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2022-09-12 22:59:35 +02:00
2022-08-12 22:57:11 +02:00
if ( p_property . name = = " animation " ) {
2016-06-08 23:03:06 +02:00
List < StringName > names ;
frames - > get_animation_list ( & names ) ;
names . sort_custom < StringName : : AlphCompare > ( ) ;
2017-03-05 16:44:50 +01:00
bool current_found = false ;
2021-11-05 21:51:42 +01:00
bool is_first_element = true ;
2016-06-08 23:03:06 +02:00
2021-11-05 21:51:42 +01:00
for ( const StringName & E : names ) {
if ( ! is_first_element ) {
2022-08-12 22:57:11 +02:00
p_property . hint_string + = " , " ;
2021-11-05 21:51:42 +01:00
} else {
is_first_element = false ;
2016-06-08 23:03:06 +02:00
}
2021-11-05 21:51:42 +01:00
p_property . hint_string + = String ( E ) ;
if ( animation = = E ) {
2017-03-05 16:44:50 +01:00
current_found = true ;
2016-06-08 23:03:06 +02:00
}
}
if ( ! current_found ) {
2022-08-12 22:57:11 +02:00
if ( p_property . hint_string . is_empty ( ) ) {
p_property . hint_string = String ( animation ) ;
2016-06-08 23:03:06 +02:00
} else {
2022-08-12 22:57:11 +02:00
p_property . hint_string = String ( animation ) + " , " + p_property . hint_string ;
2016-06-08 23:03:06 +02:00
}
}
2022-09-12 22:59:35 +02:00
return ;
2016-06-08 23:03:06 +02:00
}
2022-08-12 22:57:11 +02:00
if ( p_property . name = = " frame " ) {
2022-09-12 22:59:35 +02:00
if ( playing ) {
p_property . usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY ;
return ;
}
2022-08-12 22:57:11 +02:00
p_property . hint = PROPERTY_HINT_RANGE ;
2022-07-03 15:31:43 +02:00
if ( frames - > has_animation ( animation ) & & frames - > get_frame_count ( animation ) > 0 ) {
2022-08-12 22:57:11 +02:00
p_property . hint_string = " 0, " + itos ( frames - > get_frame_count ( animation ) - 1 ) + " ,1 " ;
2022-07-03 15:31:43 +02:00
} else {
// Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`.
2022-08-12 22:57:11 +02:00
p_property . hint_string = " 0,0,1 " ;
2016-06-08 23:03:06 +02:00
}
2022-08-12 22:57:11 +02:00
p_property . usage | = PROPERTY_USAGE_KEYING_INCREMENTS ;
2016-06-08 23:03:06 +02:00
}
}
void AnimatedSprite3D : : _notification ( int p_what ) {
2017-03-05 16:44:50 +01:00
switch ( p_what ) {
2023-01-21 06:51:03 +01:00
case NOTIFICATION_READY : {
if ( ! Engine : : get_singleton ( ) - > is_editor_hint ( ) & & ! frames . is_null ( ) & & frames - > has_animation ( autoplay ) ) {
play ( autoplay ) ;
}
} break ;
2017-01-10 22:02:19 +01:00
case NOTIFICATION_INTERNAL_PROCESS : {
2022-08-31 16:15:24 +02:00
if ( frames . is_null ( ) | | ! frames - > has_animation ( animation ) ) {
2016-06-08 23:03:06 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2022-08-31 16:15:24 +02:00
2021-02-02 03:16:37 +01:00
double remaining = get_process_delta_time ( ) ;
2022-11-26 15:00:38 +01:00
int i = 0 ;
2017-03-05 16:44:50 +01:00
while ( remaining ) {
2022-11-26 15:00:38 +01:00
// Animation speed may be changed by animation_finished or frame_changed signals.
2023-01-21 06:51:03 +01:00
double speed = frames - > get_animation_speed ( animation ) * speed_scale * custom_speed_scale * frame_speed_scale ;
double abs_speed = Math : : abs ( speed ) ;
2022-08-09 12:57:18 +02:00
2022-11-26 15:00:38 +01:00
if ( speed = = 0 ) {
return ; // Do nothing.
}
// Frame count may be changed by animation_finished or frame_changed signals.
int fc = frames - > get_frame_count ( animation ) ;
2023-01-21 06:51:03 +01:00
int last_frame = fc - 1 ;
if ( ! signbit ( speed ) ) {
// Forwards.
if ( frame_progress > = 1.0 ) {
2022-08-09 12:57:18 +02:00
if ( frame > = last_frame ) {
if ( frames - > get_animation_loop ( animation ) ) {
frame = 0 ;
2023-01-21 06:51:03 +01:00
emit_signal ( " animation_looped " ) ;
2022-08-09 12:57:18 +02:00
} else {
frame = last_frame ;
2023-01-21 06:51:03 +01:00
pause ( ) ;
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( animation_finished ) ) ;
2023-01-21 06:51:03 +01:00
return ;
2022-08-09 12:57:18 +02:00
}
2016-06-08 23:03:06 +02:00
} else {
2022-08-09 12:57:18 +02:00
frame + + ;
2016-06-08 23:03:06 +02:00
}
2023-01-21 06:51:03 +01:00
_calc_frame_speed_scale ( ) ;
frame_progress = 0.0 ;
_queue_redraw ( ) ;
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( frame_changed ) ) ;
2023-01-21 06:51:03 +01:00
}
double to_process = MIN ( ( 1.0 - frame_progress ) / abs_speed , remaining ) ;
frame_progress + = to_process * abs_speed ;
remaining - = to_process ;
} else {
// Backwards.
if ( frame_progress < = 0 ) {
2022-08-09 12:57:18 +02:00
if ( frame < = 0 ) {
if ( frames - > get_animation_loop ( animation ) ) {
frame = last_frame ;
2023-01-21 06:51:03 +01:00
emit_signal ( " animation_looped " ) ;
2022-08-09 12:57:18 +02:00
} else {
frame = 0 ;
2023-01-21 06:51:03 +01:00
pause ( ) ;
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( animation_finished ) ) ;
2023-01-21 06:51:03 +01:00
return ;
2022-08-09 12:57:18 +02:00
}
} else {
frame - - ;
}
2023-01-21 06:51:03 +01:00
_calc_frame_speed_scale ( ) ;
frame_progress = 1.0 ;
_queue_redraw ( ) ;
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( frame_changed ) ) ;
2016-06-08 23:03:06 +02:00
}
2023-01-21 06:51:03 +01:00
double to_process = MIN ( frame_progress / abs_speed , remaining ) ;
frame_progress - = to_process * abs_speed ;
remaining - = to_process ;
2016-06-08 23:03:06 +02:00
}
2022-11-26 15:00:38 +01:00
i + + ;
if ( i > fc ) {
return ; // Prevents freezing if to_process is each time much less than remaining.
}
2016-06-08 23:03:06 +02:00
}
} break ;
}
}
void AnimatedSprite3D : : set_sprite_frames ( const Ref < SpriteFrames > & p_frames ) {
2023-01-21 06:51:03 +01:00
if ( frames = = p_frames ) {
return ;
}
2020-05-14 16:41:43 +02:00
if ( frames . is_valid ( ) ) {
2024-05-13 16:56:03 +02:00
frames - > disconnect ( CoreStringName ( changed ) , callable_mp ( this , & AnimatedSprite3D : : _res_changed ) ) ;
2020-05-14 16:41:43 +02:00
}
2023-01-21 06:51:03 +01:00
stop ( ) ;
2017-03-05 16:44:50 +01:00
frames = p_frames ;
2020-05-14 16:41:43 +02:00
if ( frames . is_valid ( ) ) {
2024-05-13 16:56:03 +02:00
frames - > connect ( CoreStringName ( changed ) , callable_mp ( this , & AnimatedSprite3D : : _res_changed ) ) ;
2016-06-08 23:03:06 +02:00
2023-01-21 06:51:03 +01:00
List < StringName > al ;
frames - > get_animation_list ( & al ) ;
if ( al . size ( ) = = 0 ) {
set_animation ( StringName ( ) ) ;
2023-05-13 13:10:38 +02:00
autoplay = String ( ) ;
2023-01-21 06:51:03 +01:00
} else {
if ( ! frames - > has_animation ( animation ) ) {
2024-04-15 15:18:34 +02:00
set_animation ( al . front ( ) - > get ( ) ) ;
2023-01-21 06:51:03 +01:00
}
if ( ! frames - > has_animation ( autoplay ) ) {
2023-05-13 13:10:38 +02:00
autoplay = String ( ) ;
2023-01-21 06:51:03 +01:00
}
}
2016-06-08 23:03:06 +02:00
}
2021-02-10 21:18:45 +01:00
notify_property_list_changed ( ) ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2020-10-29 11:01:28 +01:00
update_configuration_warnings ( ) ;
2023-01-21 06:51:03 +01:00
emit_signal ( " sprite_frames_changed " ) ;
2016-06-08 23:03:06 +02:00
}
Ref < SpriteFrames > AnimatedSprite3D : : get_sprite_frames ( ) const {
return frames ;
}
void AnimatedSprite3D : : set_frame ( int p_frame ) {
2023-01-21 06:51:03 +01:00
set_frame_and_progress ( p_frame , signbit ( get_playing_speed ( ) ) ? 1.0 : 0.0 ) ;
}
int AnimatedSprite3D : : get_frame ( ) const {
return frame ;
}
void AnimatedSprite3D : : set_frame_progress ( real_t p_progress ) {
frame_progress = p_progress ;
}
real_t AnimatedSprite3D : : get_frame_progress ( ) const {
return frame_progress ;
}
void AnimatedSprite3D : : set_frame_and_progress ( int p_frame , real_t p_progress ) {
2022-08-09 12:57:18 +02:00
if ( frames . is_null ( ) ) {
2016-06-08 23:03:06 +02:00
return ;
}
2023-01-21 06:51:03 +01:00
bool has_animation = frames - > has_animation ( animation ) ;
int end_frame = has_animation ? MAX ( 0 , frames - > get_frame_count ( animation ) - 1 ) : 0 ;
bool is_changed = frame ! = p_frame ;
2016-06-08 23:03:06 +02:00
2020-05-14 16:41:43 +02:00
if ( p_frame < 0 ) {
2023-01-21 06:51:03 +01:00
frame = 0 ;
} else if ( has_animation & & p_frame > end_frame ) {
frame = end_frame ;
} else {
frame = p_frame ;
2020-05-14 16:41:43 +02:00
}
2016-06-08 23:03:06 +02:00
2023-01-21 06:51:03 +01:00
_calc_frame_speed_scale ( ) ;
frame_progress = p_progress ;
2016-06-08 23:03:06 +02:00
2023-01-21 06:51:03 +01:00
if ( ! is_changed ) {
return ; // No change, don't redraw.
}
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( frame_changed ) ) ;
2016-06-08 23:03:06 +02:00
}
2020-05-14 14:29:06 +02:00
2022-11-26 15:00:38 +01:00
void AnimatedSprite3D : : set_speed_scale ( float p_speed_scale ) {
2022-08-31 16:15:24 +02:00
speed_scale = p_speed_scale ;
2022-08-09 12:57:18 +02:00
}
2022-11-26 15:00:38 +01:00
float AnimatedSprite3D : : get_speed_scale ( ) const {
2022-08-09 12:57:18 +02:00
return speed_scale ;
}
2023-01-21 06:51:03 +01:00
float AnimatedSprite3D : : get_playing_speed ( ) const {
if ( ! playing ) {
return 0 ;
}
return speed_scale * custom_speed_scale ;
}
2016-06-08 23:03:06 +02:00
Rect2 AnimatedSprite3D : : get_item_rect ( ) const {
2022-08-31 16:15:24 +02:00
if ( frames . is_null ( ) | | ! frames - > has_animation ( animation ) ) {
return Rect2 ( 0 , 0 , 1 , 1 ) ;
}
if ( frame < 0 | | frame > = frames - > get_frame_count ( animation ) ) {
2017-03-05 16:44:50 +01:00
return Rect2 ( 0 , 0 , 1 , 1 ) ;
2016-06-08 23:03:06 +02:00
}
2019-06-11 20:43:37 +02:00
Ref < Texture2D > t ;
2020-05-14 16:41:43 +02:00
if ( animation ) {
2022-11-26 15:00:38 +01:00
t = frames - > get_frame_texture ( animation , frame ) ;
2020-05-14 16:41:43 +02:00
}
if ( t . is_null ( ) ) {
2017-03-05 16:44:50 +01:00
return Rect2 ( 0 , 0 , 1 , 1 ) ;
2020-05-14 16:41:43 +02:00
}
2021-09-25 12:18:18 +02:00
Size2 s = t - > get_size ( ) ;
2016-06-08 23:03:06 +02:00
2018-05-06 20:49:22 +02:00
Point2 ofs = get_offset ( ) ;
2023-10-06 10:38:11 +02:00
if ( is_centered ( ) ) {
2017-03-05 16:44:50 +01:00
ofs - = s / 2 ;
2020-05-14 16:41:43 +02:00
}
2016-06-08 23:03:06 +02:00
2020-05-14 16:41:43 +02:00
if ( s = = Size2 ( 0 , 0 ) ) {
2017-03-05 16:44:50 +01:00
s = Size2 ( 1 , 1 ) ;
2020-05-14 16:41:43 +02:00
}
2016-06-08 23:03:06 +02:00
2017-03-05 16:44:50 +01:00
return Rect2 ( ofs , s ) ;
2016-06-08 23:03:06 +02:00
}
void AnimatedSprite3D : : _res_changed ( ) {
2023-01-21 06:51:03 +01:00
set_frame_and_progress ( frame , frame_progress ) ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2022-11-26 15:00:38 +01:00
notify_property_list_changed ( ) ;
2016-06-08 23:03:06 +02:00
}
2023-01-21 06:51:03 +01:00
bool AnimatedSprite3D : : is_playing ( ) const {
return playing ;
}
void AnimatedSprite3D : : set_autoplay ( const String & p_name ) {
if ( is_inside_tree ( ) & & ! Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
WARN_PRINT ( " Setting autoplay after the node has been added to the scene has no effect. " ) ;
2020-05-14 16:41:43 +02:00
}
2023-01-21 06:51:03 +01:00
autoplay = p_name ;
2016-06-08 23:03:06 +02:00
}
2023-01-21 06:51:03 +01:00
String AnimatedSprite3D : : get_autoplay ( ) const {
return autoplay ;
2016-06-08 23:03:06 +02:00
}
2023-01-21 06:51:03 +01:00
void AnimatedSprite3D : : play ( const StringName & p_name , float p_custom_scale , bool p_from_end ) {
StringName name = p_name ;
if ( name = = StringName ( ) ) {
name = animation ;
}
2023-09-09 17:52:40 +02:00
ERR_FAIL_NULL_MSG ( frames , vformat ( " There is no animation with name '%s'. " , name ) ) ;
2023-01-21 06:51:03 +01:00
ERR_FAIL_COND_MSG ( ! frames - > get_animation_names ( ) . has ( name ) , vformat ( " There is no animation with name '%s'. " , name ) ) ;
2022-08-09 12:57:18 +02:00
2023-01-21 06:51:03 +01:00
if ( frames - > get_frame_count ( name ) = = 0 ) {
return ;
}
playing = true ;
custom_speed_scale = p_custom_scale ;
if ( name ! = animation ) {
animation = name ;
2024-06-24 14:30:25 +02:00
int end_frame = MAX ( 0 , frames - > get_frame_count ( animation ) - 1 ) ;
2023-01-21 06:51:03 +01:00
if ( p_from_end ) {
set_frame_and_progress ( end_frame , 1.0 ) ;
} else {
set_frame_and_progress ( 0 , 0.0 ) ;
}
2024-05-13 16:56:03 +02:00
emit_signal ( SceneStringName ( animation_changed ) ) ;
2023-01-21 06:51:03 +01:00
} else {
2024-06-24 14:30:25 +02:00
int end_frame = MAX ( 0 , frames - > get_frame_count ( animation ) - 1 ) ;
2023-01-21 06:51:03 +01:00
bool is_backward = signbit ( speed_scale * custom_speed_scale ) ;
2024-06-24 14:30:25 +02:00
2023-01-21 06:51:03 +01:00
if ( p_from_end & & is_backward & & frame = = 0 & & frame_progress < = 0.0 ) {
set_frame_and_progress ( end_frame , 1.0 ) ;
} else if ( ! p_from_end & & ! is_backward & & frame = = end_frame & & frame_progress > = 1.0 ) {
set_frame_and_progress ( 0 , 0.0 ) ;
2022-08-09 12:57:18 +02:00
}
2020-05-14 16:41:43 +02:00
}
2022-08-09 12:57:18 +02:00
2023-01-21 06:51:03 +01:00
set_process_internal ( true ) ;
2023-01-28 16:24:52 +01:00
notify_property_list_changed ( ) ;
_queue_redraw ( ) ;
2023-01-21 06:51:03 +01:00
}
void AnimatedSprite3D : : play_backwards ( const StringName & p_name ) {
play ( p_name , - 1 , true ) ;
}
void AnimatedSprite3D : : _stop_internal ( bool p_reset ) {
playing = false ;
if ( p_reset ) {
custom_speed_scale = 1.0 ;
set_frame_and_progress ( 0 , 0.0 ) ;
}
notify_property_list_changed ( ) ;
set_process_internal ( false ) ;
}
void AnimatedSprite3D : : pause ( ) {
_stop_internal ( false ) ;
2016-06-08 23:03:06 +02:00
}
2017-03-05 16:44:50 +01:00
void AnimatedSprite3D : : stop ( ) {
2023-01-21 06:51:03 +01:00
_stop_internal ( true ) ;
2016-06-08 23:03:06 +02:00
}
2022-08-09 12:57:18 +02:00
double AnimatedSprite3D : : _get_frame_duration ( ) {
if ( frames . is_valid ( ) & & frames - > has_animation ( animation ) ) {
2022-11-26 15:00:38 +01:00
return frames - > get_frame_duration ( animation , frame ) ;
2022-08-09 12:57:18 +02:00
}
2023-01-21 06:51:03 +01:00
return 1.0 ;
2022-08-09 12:57:18 +02:00
}
2023-01-21 06:51:03 +01:00
void AnimatedSprite3D : : _calc_frame_speed_scale ( ) {
frame_speed_scale = 1.0 / _get_frame_duration ( ) ;
2016-06-08 23:03:06 +02:00
}
2023-01-21 06:51:03 +01:00
void AnimatedSprite3D : : set_animation ( const StringName & p_name ) {
if ( animation = = p_name ) {
return ;
}
animation = p_name ;
2022-11-26 15:00:38 +01:00
2024-05-13 16:56:03 +02:00
emit_signal ( SceneStringName ( animation_changed ) ) ;
2023-01-21 06:51:03 +01:00
if ( frames = = nullptr ) {
animation = StringName ( ) ;
stop ( ) ;
ERR_FAIL_MSG ( vformat ( " There is no animation with name '%s'. " , p_name ) ) ;
}
int frame_count = frames - > get_frame_count ( animation ) ;
if ( animation = = StringName ( ) | | frame_count = = 0 ) {
stop ( ) ;
2016-06-08 23:03:06 +02:00
return ;
2023-01-21 06:51:03 +01:00
} else if ( ! frames - > get_animation_names ( ) . has ( animation ) ) {
animation = StringName ( ) ;
stop ( ) ;
ERR_FAIL_MSG ( vformat ( " There is no animation with name '%s'. " , p_name ) ) ;
}
if ( signbit ( get_playing_speed ( ) ) ) {
set_frame_and_progress ( frame_count - 1 , 1.0 ) ;
} else {
set_frame_and_progress ( 0 , 0.0 ) ;
2020-05-14 16:41:43 +02:00
}
2016-06-08 23:03:06 +02:00
2021-02-10 21:18:45 +01:00
notify_property_list_changed ( ) ;
2022-08-09 12:57:18 +02:00
_queue_redraw ( ) ;
2016-06-08 23:03:06 +02:00
}
2020-05-14 14:29:06 +02:00
2017-03-05 16:44:50 +01:00
StringName AnimatedSprite3D : : get_animation ( ) const {
2016-06-08 23:03:06 +02:00
return animation ;
}
2024-02-17 19:03:21 +01:00
PackedStringArray AnimatedSprite3D : : get_configuration_warnings ( ) const {
PackedStringArray warnings = SpriteBase3D : : get_configuration_warnings ( ) ;
2016-06-08 23:03:06 +02:00
if ( frames . is_null ( ) ) {
2024-07-09 20:57:25 +02:00
warnings . push_back ( RTR ( " A SpriteFrames resource must be created or set in the \" Sprite Frames \" property in order for AnimatedSprite3D to display frames. " ) ) ;
2016-06-08 23:03:06 +02:00
}
2020-10-29 11:01:28 +01:00
return warnings ;
2016-06-08 23:03:06 +02:00
}
2024-01-03 12:10:11 +01:00
# ifdef TOOLS_ENABLED
2022-05-04 14:56:20 +02:00
void AnimatedSprite3D : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
2024-01-03 12:10:11 +01:00
const String pf = p_function ;
2024-01-03 01:33:08 +01:00
if ( p_idx = = 0 & & frames . is_valid ( ) ) {
2024-01-03 12:10:11 +01:00
if ( pf = = " play " | | pf = = " play_backwards " | | pf = = " set_animation " | | pf = = " set_autoplay " ) {
2024-01-03 01:33:08 +01:00
List < StringName > al ;
frames - > get_animation_list ( & al ) ;
for ( const StringName & name : al ) {
r_options - > push_back ( String ( name ) . quote ( ) ) ;
}
2022-05-04 14:56:20 +02:00
}
}
2024-01-03 00:13:04 +01:00
SpriteBase3D : : get_argument_options ( p_function , p_idx , r_options ) ;
2022-05-04 14:56:20 +02:00
}
2024-01-03 12:10:11 +01:00
# endif
2022-05-04 14:56:20 +02:00
2023-01-21 06:51:03 +01:00
# ifndef DISABLE_DEPRECATED
bool AnimatedSprite3D : : _set ( const StringName & p_name , const Variant & p_value ) {
if ( ( p_name = = SNAME ( " frames " ) ) ) {
set_sprite_frames ( p_value ) ;
return true ;
}
return false ;
}
# endif
2016-06-08 23:03:06 +02:00
void AnimatedSprite3D : : _bind_methods ( ) {
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_sprite_frames " , " sprite_frames " ) , & AnimatedSprite3D : : set_sprite_frames ) ;
ClassDB : : bind_method ( D_METHOD ( " get_sprite_frames " ) , & AnimatedSprite3D : : get_sprite_frames ) ;
2016-06-08 23:03:06 +02:00
2023-01-21 06:51:03 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_animation " , " name " ) , & AnimatedSprite3D : : set_animation ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_animation " ) , & AnimatedSprite3D : : get_animation ) ;
2016-06-08 23:03:06 +02:00
2023-01-21 06:51:03 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_autoplay " , " name " ) , & AnimatedSprite3D : : set_autoplay ) ;
ClassDB : : bind_method ( D_METHOD ( " get_autoplay " ) , & AnimatedSprite3D : : get_autoplay ) ;
2022-08-09 13:20:07 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_playing " ) , & AnimatedSprite3D : : is_playing ) ;
2016-06-08 23:03:06 +02:00
2023-01-21 06:51:03 +01:00
ClassDB : : bind_method ( D_METHOD ( " play " , " name " , " custom_speed " , " from_end " ) , & AnimatedSprite3D : : play , DEFVAL ( StringName ( ) ) , DEFVAL ( 1.0 ) , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " play_backwards " , " name " ) , & AnimatedSprite3D : : play_backwards , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " pause " ) , & AnimatedSprite3D : : pause ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " stop " ) , & AnimatedSprite3D : : stop ) ;
2016-06-08 23:03:06 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_frame " , " frame " ) , & AnimatedSprite3D : : set_frame ) ;
ClassDB : : bind_method ( D_METHOD ( " get_frame " ) , & AnimatedSprite3D : : get_frame ) ;
2016-06-08 23:03:06 +02:00
2023-01-21 06:51:03 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_frame_progress " , " progress " ) , & AnimatedSprite3D : : set_frame_progress ) ;
ClassDB : : bind_method ( D_METHOD ( " get_frame_progress " ) , & AnimatedSprite3D : : get_frame_progress ) ;
ClassDB : : bind_method ( D_METHOD ( " set_frame_and_progress " , " frame " , " progress " ) , & AnimatedSprite3D : : set_frame_and_progress ) ;
2022-08-09 12:57:18 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_speed_scale " , " speed_scale " ) , & AnimatedSprite3D : : set_speed_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " get_speed_scale " ) , & AnimatedSprite3D : : get_speed_scale ) ;
2023-01-21 06:51:03 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_playing_speed " ) , & AnimatedSprite3D : : get_playing_speed ) ;
2022-08-09 12:57:18 +02:00
2021-06-30 03:55:11 +02:00
ClassDB : : bind_method ( D_METHOD ( " _res_changed " ) , & AnimatedSprite3D : : _res_changed ) ;
2023-01-21 06:51:03 +01:00
ADD_SIGNAL ( MethodInfo ( " sprite_frames_changed " ) ) ;
ADD_SIGNAL ( MethodInfo ( " animation_changed " ) ) ;
2016-06-08 23:03:06 +02:00
ADD_SIGNAL ( MethodInfo ( " frame_changed " ) ) ;
2023-01-21 06:51:03 +01:00
ADD_SIGNAL ( MethodInfo ( " animation_looped " ) ) ;
2020-07-12 14:39:21 +02:00
ADD_SIGNAL ( MethodInfo ( " animation_finished " ) ) ;
2016-06-08 23:03:06 +02:00
2023-01-21 06:51:03 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " sprite_frames " , PROPERTY_HINT_RESOURCE_TYPE , " SpriteFrames " ) , " set_sprite_frames " , " get_sprite_frames " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING_NAME , " animation " , PROPERTY_HINT_ENUM , " " ) , " set_animation " , " get_animation " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING_NAME , " autoplay " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR ) , " set_autoplay " , " get_autoplay " ) ;
2019-07-25 09:11:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " frame " ) , " set_frame " , " get_frame " ) ;
2023-01-21 06:51:03 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " frame_progress " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR ) , " set_frame_progress " , " get_frame_progress " ) ;
2022-08-09 12:57:18 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " speed_scale " ) , " set_speed_scale " , " get_speed_scale " ) ;
2016-06-08 23:03:06 +02:00
}
AnimatedSprite3D : : AnimatedSprite3D ( ) {
}