diff --git a/exemple_delacre/Sprite_0006_XY.png b/exemple_delacre/Sprite_0006_XY.png new file mode 100644 index 0000000..7e40a3c Binary files /dev/null and b/exemple_delacre/Sprite_0006_XY.png differ diff --git a/exemple_delacre/Sprite_0006_dos_XY.png b/exemple_delacre/Sprite_0006_dos_XY.png new file mode 100644 index 0000000..bc1dfcd Binary files /dev/null and b/exemple_delacre/Sprite_0006_dos_XY.png differ diff --git a/exemple_delacre/Sprite_0009_XY.png b/exemple_delacre/Sprite_0009_XY.png new file mode 100644 index 0000000..e055300 Binary files /dev/null and b/exemple_delacre/Sprite_0009_XY.png differ diff --git a/exemple_delacre/Sprite_0477_XY.png b/exemple_delacre/Sprite_0477_XY.png new file mode 100644 index 0000000..32056b2 Binary files /dev/null and b/exemple_delacre/Sprite_0477_XY.png differ diff --git a/exemple_delacre/Sprite_0477_dos_XY.png b/exemple_delacre/Sprite_0477_dos_XY.png new file mode 100644 index 0000000..056edcd Binary files /dev/null and b/exemple_delacre/Sprite_0477_dos_XY.png differ diff --git a/exemple_delacre/battle.gd b/exemple_delacre/battle.gd new file mode 100644 index 0000000..da11434 --- /dev/null +++ b/exemple_delacre/battle.gd @@ -0,0 +1,64 @@ +extends Node2D +@onready var compute_shader = $ComputeShaderStudio2D +var attack_time = 0.0 +var attack_progress = 0.0 +var is_attacking = false +var current_attack = "none" + +func _ready(): + # Initialiser les uniformes pour qu'ils soient disponibles dans le shader + compute_shader.set_shader_parameter("TIME", 0.0) + compute_shader.set_shader_parameter("PROGRESS", 0.0) + compute_shader.set_shader_parameter("CENTER_X", 0.0) + compute_shader.set_shader_parameter("CENTER_Y", 0.0) + compute_shader.set_shader_parameter("TARGET_X", 0.0) + compute_shader.set_shader_parameter("TARGET_Y", 0.0) + compute_shader.set_shader_parameter("ATTACK_TYPE", 0) # 0=aucune, 1=vibrobscur, 2=lance-flammes + +func _process(delta): + if is_attacking: + attack_time += delta + attack_progress = min(attack_time / 2.0, 1.0) # Animation de 2 secondes + + # Mettre à jour les uniformes + compute_shader.set_shader_parameter("TIME", attack_time) + compute_shader.set_shader_parameter("PROGRESS", attack_progress) + + # Fin de l'animation + if attack_progress >= 1.0: + is_attacking = false + # Réinitialiser l'effet + reset_attack() + +func use_dark_pulse(source_x = 0, source_y = 0): + current_attack = "dark_pulse" + is_attacking = true + attack_time = 0.0 + attack_progress = 0.0 + + # Définir les paramètres pour Vibrobscur + compute_shader.set_shader_parameter("CENTER_X", float(source_x)) + compute_shader.set_shader_parameter("CENTER_Y", float(source_y)) + compute_shader.set_shader_parameter("TIME", 0.0) + compute_shader.set_shader_parameter("PROGRESS", 0.0) + compute_shader.set_shader_parameter("ATTACK_TYPE", 1) # 1 = Vibrobscur + +func use_flamethrower(source_x = 0, source_y = 0, target_x = 0, target_y = 0): + current_attack = "flamethrower" + is_attacking = true + attack_time = 0.0 + attack_progress = 0.0 + + # Définir les paramètres pour Lance-Flammes + compute_shader.set_shader_parameter("CENTER_X", float(source_x)) + compute_shader.set_shader_parameter("CENTER_Y", float(source_y)) + compute_shader.set_shader_parameter("TARGET_X", float(target_x)) + compute_shader.set_shader_parameter("TARGET_Y", float(target_y)) + compute_shader.set_shader_parameter("TIME", 0.0) + compute_shader.set_shader_parameter("PROGRESS", 0.0) + compute_shader.set_shader_parameter("ATTACK_TYPE", 2) # 2 = Lance-Flammes + +func reset_attack(): + # Réinitialiser à l'état sans attaque + current_attack = "none" + compute_shader.set_shader_parameter("ATTACK_TYPE", 0) diff --git a/exemple_delacre/fond.jpg b/exemple_delacre/fond.jpg new file mode 100644 index 0000000..c5bef65 Binary files /dev/null and b/exemple_delacre/fond.jpg differ diff --git a/exemple_delacre/script.txt b/exemple_delacre/script.txt new file mode 100644 index 0000000..130e224 --- /dev/null +++ b/exemple_delacre/script.txt @@ -0,0 +1,340 @@ +extends Node +class_name ComputeShaderStudio2D + +var current_pass : int = 0 + +# Put your GLSL code in the GLSL_main string below +# Here are all the accessible variables (uniforms) inside your GLSL code: +# uint x,y : from GlobalInvocationID.x and .y +# uint p : the position [x][y] in the invocation +# uint WSX,WSY : the Global WorkSpace of invocations (generally match the data size) +# int* data_0, data_1, etc : are the data treated (can be displayed by Sprite2D, TextureRect, etc). +# Access them by data_0[p], data_1[p], etc +# uint step : simulation step of the execution. Incresed by 1 after nb_passes +# uint nb_passes: the number of passes your code needs (by step). +# There is a barrier between each pass. +# uint current_pass: pass currently executed (one pass per frame, nb_passes by step) + +#region ComputeShaderStudio + +var GLSL_header = """ +#version 450 + +// Invocations in the (x, y, z) dimension +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +// Bindings to the buffers we create in our script +layout(binding = 0) buffer Params { + int step; + int current_pass; + int mousex; + int mousey; +}; + +""" + + +## Print the current step. +@export var print_step:bool = false +## Print the current pass. +@export var print_passes:bool = false +## Print in Output all the generated code. +## Can be usefull for debugging or to understand all the GLSL code needed. +@export var print_generated_code:bool = false +## Do not execute compute shader at launch. +@export var pause:bool = false +## Number of passes into each execution step. +## Between two passes, your GLSL code is synchronized. +@export var nb_passes : int = 1 +## Workspace Size X, usually it matches the x size of your image (Sprite2D or TextureRect) +@export var WSX : int = 128 +## Workspace Size Y, usually it matches the y size of your image (Sprite2D or TextureRect) +@export var WSY : int = 128 + +## Drag & drop your external GLSL file here (use .cpp for your source file extension) +@export_file("*.cpp") var glsl_file: String +## Write your GLSL code just below or use an external file above +@export_multiline var GLSL_code : String = """ +// Write your code HERE +void main() { + uint x = gl_GlobalInvocationID.x; + uint y = gl_GlobalInvocationID.y; + uint p = x + y * WSX; + data_0[p] = 0xFFF00FFF - int(p)*(step+1); + data_1[p] = 0xFF0000AA + int( 1.0 + 99999.9*sin(float(x+float(step+y))/1000.0)); +} +""" +## Drag and drop here your Sprite2D or TextureRect. +@export var data:Array[Node] + +var rd : RenderingDevice +var shader : RID +var buffers : Array[RID] +var buffer_params : RID +var buffer_user : RID + +var uniforms : Array[RDUniform] +#var uniform_2 : RDUniform +var uniform_params : RDUniform +var uniform_user : RDUniform + +var uniform_user_data : PackedByteArray = PackedByteArray([0]) + +var bindings : Array = [] + +var pipeline : RID +var uniform_set : RID + +# Called when the node enters the scene tree for the first time. +#region _ready +func _ready(): + # Chargement de l'image en tant que texture + var fond_texture = load("res://exemple_ewann/fond.jpg") + $Fond.material.set_shader_parameter("fond_texture", fond_texture) + compile() + +func compile(): + # Create a local rendering device. + rd = RenderingServer.create_local_rendering_device() + if not rd: + set_process(false) + printerr("Compute shaders are not available") + return + + # ********************* + # * SHADER CREATION * + # ********************* + + var nb_buffers : int = data.size() + + # Create GLSL Header + GLSL_header += """ +uint WSX="""+str(WSX)+""";"""+""" +uint WSY="""+str(WSY)+"""; +""" + + for i in nb_buffers: + GLSL_header += """ +layout(binding = """+str(i+2)+""") buffer Data"""+str(i)+""" { + int data_"""+str(i)+"""[]; +}; + +""" + + # The external GLSL file takes priority + if glsl_file != "": + print("Load the GLSL file:" + glsl_file ) + GLSL_code = load_glsl_file(glsl_file) + var GLSL_all : String = GLSL_header + GLSL_code + if print_generated_code == true: + print(GLSL_all) + + # Compile the shader by passing a string + var shader_src := RDShaderSource.new() + shader_src.set_stage_source(RenderingDevice.SHADER_STAGE_COMPUTE, GLSL_all) + var shader_spirv := rd.shader_compile_spirv_from_source(shader_src) + + var err:String=shader_spirv.compile_error_compute + + if err != "": + printerr(err) + get_tree().quit() + + shader = rd.shader_create_from_spirv(shader_spirv) + + + # ********************* + # * BUFFERS CREATION * + # ********************* + + # Buffer for current_pass + var input_params :PackedInt32Array = PackedInt32Array() + input_params.append(step) + input_params.append(current_pass) + var input_params_bytes := input_params.to_byte_array() + buffer_params = rd.storage_buffer_create(input_params_bytes.size(), input_params_bytes) + buffer_user = rd.storage_buffer_create(uniform_user_data.size(), uniform_user_data) + + # Creation of nb_buffers Buffers of type Int32 + for b in nb_buffers: + var input :PackedInt32Array = PackedInt32Array() + for i in range(WSX): + for j in range(WSY): + input.append(randi()) + var input_bytes :PackedByteArray = input.to_byte_array() + buffers.append(rd.storage_buffer_create(input_bytes.size(), input_bytes)) + + # ********************* + # * UNIFORMS CREATION * + # ********************* + + # Create current_pass uniform pass + uniform_params = RDUniform.new() + uniform_params.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER + uniform_params.binding = 0 # this needs to match the "binding" in our shader file + uniform_params.add_id(buffer_params) + + # Create current_pass uniform pass + uniform_user = RDUniform.new() + uniform_user.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER + uniform_user.binding = 1 # this needs to match the "binding" in our shader file + uniform_user.add_id(buffer_user) + + var nb_uniforms : int = data.size() + for b in nb_uniforms: + var uniform = RDUniform.new() + uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER + uniform.binding = b+2 # this needs to match the "binding" in our shader file + uniform.add_id(buffers[b]) + uniforms.append(uniform) + + # Create the uniform SET between CPU & GPU + bindings = [uniform_params, uniform_user] + for b in nb_buffers: + bindings.append(uniforms[b]) + + uniform_set = rd.uniform_set_create(bindings, shader, 0) # the last parameter (the 0) needs to match the "set" in our shader file + + # ************************** + # * COMPUTE LIST CREATION * + # ************************** + # Create a compute pipeline + pipeline = rd.compute_pipeline_create(shader) + +#endregion + +func load_glsl_file(file_name:String) -> String: + var file = FileAccess.open(file_name, FileAccess.READ) + if file == null: + printerr("Unable to load GLSL file:" + file_name) + return "void main() {}" + var src_glsl:String = file.get_as_text() + return src_glsl + +func display_all_values(): + # Read back the data from the buffers + for b in data.size(): + var output_bytes : PackedByteArray = rd.buffer_get_data(buffers[b]) + if is_instance_valid(data[b]): + display_values(data[b], output_bytes) + +func display_values(disp : Node, values : PackedByteArray): # PackedInt32Array): + var img : Image = Image.create_from_data(WSX, WSY, false, Image.FORMAT_RGBA8, values) + var tex : Texture2D = ImageTexture.create_from_image(img) + + if disp is Sprite2D : + var old_width : float = disp.texture.get_width() + var old_height : float = disp.texture.get_height() + disp.set_texture(tex) + disp.scale *= Vector2(old_width/WSX, old_height/WSY) + + else : + disp.set_texture(tex) + + +var step : int = 0 + +func compute(): + if print_step == true && current_pass%nb_passes == 0: + print("Step="+str(step)) + if print_passes == true: + print(" CurrentPass="+str(current_pass)) + + _update_uniforms() + + # Prepare the Computer List ############################################ + var compute_list : int = rd.compute_list_begin() + rd.compute_list_bind_compute_pipeline(compute_list, pipeline) + rd.compute_list_bind_uniform_set(compute_list, uniform_set, 0) + rd.compute_list_dispatch(compute_list, WSX>>3, WSY>>3, 1) + rd.compute_list_end() + ####################################################################### + + # Submit to GPU and wait for sync + rd.submit() + rd.sync() + + # Update step and current_passe + current_pass = (current_pass + 1) % nb_passes + if current_pass == 0: + step += 1 + +func _process(_delta): + + if pause == false: + compute() + display_all_values() + +## Pass the interesting values from CPU to GPU +func _update_uniforms(): + var input_params : PackedInt32Array = PackedInt32Array() + + input_params.append(step) + input_params.append(current_pass) + + var pos : Vector2 = screen_to_data0(get_viewport().get_mouse_position()) + input_params.append(pos.x) + input_params.append(pos.y) + + var input_params_bytes := input_params.to_byte_array() + buffer_params = rd.storage_buffer_create(input_params_bytes.size(), input_params_bytes) + uniform_params = RDUniform.new() + uniform_params.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER + uniform_params.binding = 0 # this needs to match the "binding" in our shader file + uniform_params.add_id(buffer_params) + bindings[0] = uniform_params + + buffer_user = rd.storage_buffer_create(uniform_user_data.size(), uniform_user_data) + uniform_user = RDUniform.new() + uniform_user.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER + uniform_user.binding = 1 # this needs to match the "binding" in our shader file + uniform_user.add_id(buffer_user) + bindings[1] = uniform_user + + uniform_set = rd.uniform_set_create(bindings, shader, 0) + # Note: when changing the uniform set, use the same bindings Array (do not create a new Array) + +## Cleaning up the GPU resources +func _notification(what): + # Object destructor, triggered before the engine deletes this Node. + if what == NOTIFICATION_PREDELETE: + cleanup_gpu() + +func cleanup_gpu(): + if rd == null: + return + # All resources must be freed after use to avoid memory leaks. + rd.free_rid(pipeline) + pipeline = RID() + + rd.free_rid(uniform_set) + uniform_set = RID() + + rd.free_rid(shader) + shader = RID() + + rd.free() + rd = null + +#endregion + +func _on_button_step(): + pause = true + compute() + display_all_values() + + +func _on_button_play(): + pause = false # Replace with function body. + +func screen_to_data0(pos : Vector2): + if data.size() <= 0 : + return Vector2(0, 0) + + if data[0] is Sprite2D: + var sprite : Sprite2D = data[0] + pos.x = (pos.x - sprite.position.x) / sprite.scale.x + WSX/2 + pos.y = (pos.y - sprite.position.y) / sprite.scale.y + WSY/2 + return pos; + else: + return Vector2(0,0) diff --git a/exemple_delacre/source.cpp b/exemple_delacre/source.cpp new file mode 100644 index 0000000..0695813 --- /dev/null +++ b/exemple_delacre/source.cpp @@ -0,0 +1,81 @@ +void main() { + uint x = gl_GlobalInvocationID.x; + uint y = gl_GlobalInvocationID.y; + uint p = x + y * WSX; + + // Délai avant démarrage (2 secondes à ~60fps) + int delay = 120; + int delay_vibraqua = delay + 180; // Lance-Flammes démarre après ~4 secondes (240 frames total) + + // --- Vibrobscur (data_0) --- + if (step < delay) { + data_0[p] = 0x00000000; // Transparent + } else { + // Coordonnées normalisées + float fx = float(x) / WSX * 2.0 - 1.0; + float fy = float(y) / WSY * 2.0 - 1.0; + + // Temps d'animation pour Vibrobscur + float time = float(step - delay) * 0.02; + float max_radius = 0.6; + float base_radius = min(0.1 + time, max_radius); + + // Ondulation sinusoïdale avec plus de variabilité pour les bords + float wave = 0.03 * sin(10.0 * fx + time * 5.0) * cos(10.0 * fy + time * 5.0); + wave += 0.05 * sin(20.0 * fx + time * 3.0); // Déformation supplémentaire + float radius = base_radius + wave; + + // Masque de transition (bords plus chaotiques) + float dist = sqrt(fx * fx + fy * fy); + float mask = smoothstep(radius, radius - 0.05 - wave * 0.5, dist); + + // Effet de distorsion dynamique + float distortion = sin(time * 3.0 + fx * 10.0) * cos(time * 3.0 + fy * 10.0); + int color_shift = int((distortion + 1.0) * 0.5 * 2.0) % 2; // Change entre 0 et 1 + int color = color_shift == 0 ? 0x000000 : 0x880088; // Noir ou violet foncé + + int alpha = int(mask * 255.0) << 24; // Opacité progressive + + // Stockage dans data_0 pour Vibrobscur + data_0[p] = alpha + color; + } + + // --- Vibraqua (data_1) --- + if (step < delay_vibraqua) { + data_1[p] = 0x00000000; // Transparent + } else { + // Coordonnées normalisées + float fx = float(x) / WSX * 2.0 - 1.0; + float fy = float(y) / WSY * 2.0 - 1.0; + + // Temps d'animation pour Vibraqua + float time = float(step - delay_vibraqua) * 0.03; // Réduire la vitesse de l'attaque + + // L'attaque commence par un rayon plus petit et s'agrandit plus lentement + float max_radius = 1.0; // Taille finale plus petite + float base_radius = min(0.1 + time * 0.35, max_radius); // L'attaque grandit plus lentement + + // Forme allongée pour simuler l'eau, avec une distorsion dynamique + float dist = sqrt(fx * fx + fy * fy); // Distance au centre + float angle = atan(fy, fx); // Calculer l'angle pour donner une forme conique + + // Masque de transition plus large avec distorsion + float mask = smoothstep(base_radius, base_radius - 0.05, dist) * (1.0 - 0.2 * abs(angle)); + + // Couleurs + int red = int(mask * (0xFF)); + int green = int(mask * (0x50)); + int blue = 0; + + int alpha = int(mask * 255.0) << 24; // Opacité progressive + + // Effet de distorsion dynamique + float distortion = sin(time * 8.0 + fx * 10.0) * cos(time * 8.0 + fy * 10.0); + red = int(float(red) * (1.0 + distortion * 0.5)); + green = int(float(green) * (1.0 + distortion * 0.2)); + + // Stockage dans data_1 pour Vibraqua + int color = (red << 16) + (green << 8) + blue; + data_1[p] = alpha + color; + } +} diff --git a/exemple_delacre/source.txt b/exemple_delacre/source.txt new file mode 100644 index 0000000..53122b1 --- /dev/null +++ b/exemple_delacre/source.txt @@ -0,0 +1,81 @@ +void main() { + uint x = gl_GlobalInvocationID.x; + uint y = gl_GlobalInvocationID.y; + uint p = x + y * WSX; + + // Délai avant démarrage (2 secondes à ~60fps) + int delay = 120; + int delay_lance_flame = delay + 180; // Lance-Flammes démarre après ~4 secondes (240 frames total) + + // --- Vibrobscur (data_0) --- + if (step < delay) { + data_0[p] = 0x00000000; // Transparent + } else { + // Coordonnées normalisées + float fx = float(x) / WSX * 2.0 - 1.0; + float fy = float(y) / WSY * 2.0 - 1.0; + + // Temps d'animation pour Vibrobscur + float time = float(step - delay) * 0.02; + float max_radius = 0.6; + float base_radius = min(0.1 + time, max_radius); + + // Ondulation sinusoïdale avec plus de variabilité pour les bords + float wave = 0.03 * sin(10.0 * fx + time * 5.0) * cos(10.0 * fy + time * 5.0); + wave += 0.05 * sin(20.0 * fx + time * 3.0); // Déformation supplémentaire + float radius = base_radius + wave; + + // Masque de transition (bords plus chaotiques) + float dist = sqrt(fx * fx + fy * fy); + float mask = smoothstep(radius, radius - 0.05 - wave * 0.5, dist); + + // Effet de distorsion dynamique + float distortion = sin(time * 3.0 + fx * 10.0) * cos(time * 3.0 + fy * 10.0); + int color_shift = int((distortion + 1.0) * 0.5 * 2.0) % 2; // Change entre 0 et 1 + int color = color_shift == 0 ? 0x000000 : 0x880088; // Noir ou violet foncé + + int alpha = int(mask * 255.0) << 24; // Opacité progressive + + // Stockage dans data_0 pour Vibrobscur + data_0[p] = alpha + color; + } + + // --- Lance-Flammes (data_1) --- + if (step < delay_lance_flame) { + data_1[p] = 0x00000000; // Transparent + } else { + // Coordonnées normalisées + float fx = float(x) / WSX * 2.0 - 1.0; + float fy = float(y) / WSY * 2.0 - 1.0; + + // Temps d'animation pour Lance-Flammes + float time = float(step - delay_lance_flame) * 0.03; // Réduire la vitesse de l'attaque + + // L'attaque commence par un rayon plus petit et s'agrandit plus lentement + float max_radius = 1.0; // Taille finale plus petite + float base_radius = min(0.1 + time * 0.35, max_radius); // L'attaque grandit plus lentement + + // Forme allongée pour simuler la flamme, avec une distorsion dynamique + float dist = sqrt(fx * fx + fy * fy); // Distance au centre + float angle = atan(fy, fx); // Calculer l'angle pour donner une forme conique + + // Masque de transition plus large avec distorsion + float mask = smoothstep(base_radius, base_radius - 0.05, dist) * (1.0 - 0.2 * abs(angle)); + + // Couleur de la flamme (rouge/orange) + int red = int(mask * (0xFF)); // Rouge vif + int green = int(mask * (0x50)); // Un peu plus de vert pour l'effet de flamme + int blue = 0; // Pas de bleu pour l'effet de flamme + + int alpha = int(mask * 255.0) << 24; // Opacité progressive + + // Effet de distorsion dynamique pour plus de chaleur + float distortion = sin(time * 8.0 + fx * 10.0) * cos(time * 8.0 + fy * 10.0); + red = int(float(red) * (1.0 + distortion * 0.5)); // Amplifier le rouge selon la distorsion + green = int(float(green) * (1.0 + distortion * 0.2)); // Amplifier légèrement le vert + + // Stockage dans data_1 pour Lance-Flammes + int color = (red << 16) + (green << 8) + blue; + data_1[p] = alpha + color; + } +}