import json import math import os import raylibpy as raylib import ctypes from settings import * # === Functions === # Function to return the formatted transformation matrix (4x4 column-major order) def get_transform_matrix(*args): # Convert all parameters to float a, b, c, d, tx, ty = map(float, args) # Ensure a proper 4x4 transformation matrix in column-major order transform_matrix = [ a, b, 0.0, 0.0, c, d, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, tx, ty, 0.0, 1.0 ] return transform_matrix # Function to return transformed image def transform_image(image, *transform_values): # Get transformation matrix transform_matrix = get_transform_matrix(*transform_values) # Convert the list to a ctypes array of floats matrix_array = (ctypes.c_float * 16)(*transform_matrix) image_size = (image.width, image.height) # Get new image bounding box offset_x, offset_y, dynamic_width, dynamic_height = ( get_new_bounding_box(image_size, *transform_values)) print(offset_x, offset_y, dynamic_width, dynamic_height) # Load render texture with correct coordinates render_texture = raylib.load_render_texture(dynamic_width, dynamic_height) # Set texture filter to bilinear for smoother scaling raylib.set_texture_filter(render_texture.texture, raylib.TEXTURE_FILTER_BILINEAR) # -- Render transformed image onto the render texture -- raylib.begin_texture_mode(render_texture) raylib.clear_background(raylib.BLANK) # Apply transformation raylib.rl_push_matrix() raylib.rl_load_identity() # Reset to identity so no previous transform interference raylib.rl_translatef(-offset_x, -offset_y, 0) raylib.rl_mult_matrixf(matrix_array) # Draw the input image onto the render texture img_texture = raylib.load_texture_from_image(image) raylib.set_texture_filter(img_texture, raylib.TEXTURE_FILTER_BILINEAR) # raylib.draw_rectangle(0, 0, image.width, image.height, raylib.RED) raylib.draw_texture_pro( img_texture, raylib.Rectangle(0, 0, image.width, -image.height), # Flip Y raylib.Rectangle(0, 0, image.width, image.height), raylib.Vector2(0, 0), 0, raylib.WHITE ) # raylib.unload_texture(img_texture) # Close matrix transform raylib.rl_pop_matrix() raylib.end_texture_mode() # Return the transformed image and the offsets return render_texture, offset_x, offset_y # Function to build and transform sprite texture def build_and_transform_sprite(): pass # Get bounding box of new image post-transform def get_new_bounding_box(image_dimensions, *transform_values): # Unpack and convert transform values to floats a, b, c, d, tx, ty = map(float, transform_values) # Define original corners original_corners = [ (0, 0), (image_dimensions[0], 0), (0, image_dimensions[1]), image_dimensions ] # Apply transformations to each corner transformed_corners = [(a * x + c * y + tx, b * x + d * y + ty) for (x, y) in original_corners] # Bruteforce get min and max x and y values x_list = [point[0] for point in transformed_corners] y_list = [point[1] for point in transformed_corners] min_x = math.floor(min(x_list)) max_x = math.floor(max(x_list)) min_y = math.floor(min(y_list)) max_y = math.floor(max(y_list)) new_width = int(max_x - min_x) new_height = int(max_y - min_y) new_bounding_box_values = (min_x - TEXTURE_PIXEL_PADDING, min_y - TEXTURE_PIXEL_PADDING, new_width + TEXTURE_PIXEL_PADDING, new_height + TEXTURE_PIXEL_PADDING) return new_bounding_box_values # === Program === # Initialize raylib raylib.set_trace_log_level(raylib.LOG_WARNING) raylib.set_config_flags(raylib.FLAG_WINDOW_RESIZABLE) raylib.init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "PAM Interpreter Test") raylib.set_target_fps(30) # JSON input json_input_path = os.path.join(INPUT_PATH, JSON_INPUT) with open(json_input_path) as file: json_file = json.load(file) # Store relevant header data json_header_data = json_file["header_data"] anim_dimensions = json_header_data["anim_dimensions"] anim_frame_rate = json_header_data["anim_frame_rate"] action_command_data = json_header_data["action_script_data"] # -- 01 Media images -> Image images -- json_raw_images_data: dict = json_file["raw_images_data"] raw_images_data = [] # Stores the render texture and base offsets in each name entry base_images_data = {} # Get every entry in images data dict for image_name, image_info in json_raw_images_data.items(): image_data = { 'name': image_name, 'image_path': image_info['image_path'], 'transform_values': image_info['transform_values'] } raw_images_data.append(image_data) # Load every image referenced for image_data in raw_images_data: base_image_path = image_data['image_path'] + IMAGE_FILE_EXTENSION split_image_path = base_image_path.split('/') # Input the unpacked list i.e. one by one full_image_path = os.path.join(INPUT_PATH, *split_image_path) raw_base_image = raylib.load_image(full_image_path) # Apply first transforms transform_values = image_data['transform_values'] transformed_base_image = transform_image(raw_base_image, *transform_values) render_texture, offset_x, offset_y = transformed_base_image base_images_data[image_data['name']] = { 'render_texture': render_texture, 'offset_dimensions': (offset_x, offset_y) } # Cleanup media images raylib.unload_image(raw_base_image) # -- 02 Image images -> Sprite images -- json_sprite_textures_data = json_file["sprite_textures_data"] print(json_sprite_textures_data) # Stores the images and transform data for each sprite sprite_assets_data = {} # Stores the completed sprites as images sprite_textures_data = {} # Load sprite data for sprite_name, sprite_data in json_sprite_textures_data.items(): sprite_assets_data[sprite_name] = [] print(sprite_name) for layer in sprite_data: split_layer_texture_name = layer["texture_name"].split('/') layer_texture_type = split_layer_texture_name[0] layer_texture_name = split_layer_texture_name[1] layer_transform_values = layer["transform_values"] layer_color_transform = layer["color_values"] layer_data = { 'texture_name': layer_texture_name, 'texture_type': layer_texture_type, 'transform_values': layer_transform_values, 'color_values': layer_color_transform } # Save the layer data sprite_assets_data[sprite_name].append(layer_data) # Build each sprite from its layers for sprite_name, sprite_layers in sprite_assets_data.items(): sprite_layer_assets = [] print(sprite_name, sprite_layers) for layer in sprite_layers: texture_name = layer["texture_name"] texture_type = layer["texture_type"] # Handle raw images if texture_type == "image": raw_layer_asset = base_images_data[texture_name] # Handle sprites elif texture_type == "sprite": # Handle undefined sprites try: raw_layer_asset = sprite_textures_data[texture_name] except Exception as e: raw_layer_asset = None print(f"ERROR: {e}") else: print("unsupported layer type") raw_layer_asset = None # Transform image if raw_layer_asset is None: print("None") pass else: print(raw_layer_asset) # Transform raw_layer_asset_texture = raw_layer_asset["render_texture"].texture raw_layer_asset_image = raylib.load_image_from_texture(raw_layer_asset_texture) # Save transformed image layer_asset_texture = transform_image(raw_layer_asset_image, *layer["transform_values"]) sprite_layer_assets.append({ 'render_texture': layer_asset_texture[0], 'offset_values': (layer_asset_texture[1], layer_asset_texture[2]) }) # Build sprite from images sprite_data = None for sprite in sprite_layer_assets: pass print(sprite_layer_assets) # === Main Loop === while not raylib.window_should_close(): raylib.begin_drawing() raylib.clear_background(raylib.RAYWHITE) raylib.draw_fps(5, 5) for tex_name, tex_data in base_images_data.items(): # print(tex_name) raylib.draw_texture(tex_data['render_texture'].texture, tex_data['offset_dimensions'][0], tex_data['offset_dimensions'][1], raylib.RAYWHITE) raylib.end_drawing() # --- Shutdown Sequence --- raylib.close_window()