/mnt/c/Users/Jeff/logo  python3 main_script.py                                                    ok  5s  09:03:16 AM
Applied effect: rotate
Error: No ID block and/or AnimData to delete keyframe from
An error occurred while applying effect 'neon': Error: No ID block and/or AnimData to delete keyframe from

MESA: error: ZINK: failed to choose pdev
glx: failed to create drisw screen
Warning: No OpenGL vendor detected.
python3.11: ../external_epoxy/src/dispatch_common.c:872: epoxy_get_proc_address: Assertion `0 && "Couldn't find current GLX or EGL context.\n"' failed.
[1]    1082 IOT instruction (core dumped)  python3.11 main_script.py import bpy
import json
import os
import math
import importlib
from mathutils import Vector

class LogoAnimator:
    def __init__(self, project_dir):
        self.project_dir = project_dir
        self.logo_path = os.path.join(project_dir, "logo.png")
        self.config_path = os.path.join(project_dir, "config.json")
        self.effects_dir = os.path.join(project_dir, "effects")
        
        # Ensure the effects directory is in the system path
        if self.effects_dir not in os.sys.path:
            os.sys.path.append(self.effects_dir)
            
    def setup_scene(self):
        # Clear existing scene
        bpy.ops.object.select_all(action='SELECT')
        bpy.ops.object.delete()
        
        # Set up render settings
        bpy.context.scene.render.resolution_x = 1024
        bpy.context.scene.render.resolution_y = 1024
        bpy.context.scene.render.film_transparent = True
        bpy.context.scene.render.image_settings.file_format = 'PNG'
        bpy.context.scene.render.image_settings.color_mode = 'RGBA'
        
        # Set up animation settings based on config
        config = self.load_config()
        frame_end = config.get("frame_end", 60)
        bpy.context.scene.frame_start = 0
        bpy.context.scene.frame_end = frame_end

        # Add a camera to the scene
        bpy.ops.object.camera_add(location=(0, -3, 2), rotation=(1.1, 0, 0))
        bpy.context.scene.camera = bpy.context.object  # Set the camera as the scene's active camera
        
    def create_logo_plane(self):
        # Create a plane
        bpy.ops.mesh.primitive_plane_add(size=2)
        logo_plane = bpy.context.active_object
        
        # Add material with logo texture
        mat = bpy.data.materials.new(name="LogoMaterial")
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        
        # Clear default nodes
        nodes.clear()
        
        # Create nodes
        texture_coord = nodes.new('ShaderNodeTexCoord')
        mapping = nodes.new('ShaderNodeMapping')
        image_tex = nodes.new('ShaderNodeTexImage')
        emission = nodes.new('ShaderNodeEmission')
        output = nodes.new('ShaderNodeOutputMaterial')
        
        # Load and assign image
        image_tex.image = bpy.data.images.load(self.logo_path)
        image_tex.image.colorspace_settings.is_data = False  # Ensure proper color space
        
        # Connect nodes
        links = mat.node_tree.links
        links.new(texture_coord.outputs['UV'], mapping.inputs['Vector'])
        links.new(mapping.outputs['Vector'], image_tex.inputs['Vector'])
        links.new(image_tex.outputs['Color'], emission.inputs['Color'])
        links.new(image_tex.outputs['Alpha'], emission.inputs['Strength'])  # Control emission strength with alpha
        links.new(emission.outputs['Emission'], output.inputs['Surface'])
        
        # Assign material to plane
        logo_plane.data.materials.append(mat)
        
        return logo_plane
            
    def load_config(self):
        with open(self.config_path, 'r') as f:
            return json.load(f)
            
    def setup_output(self, output_path):
        # Ensure the output directory exists
        os.makedirs(os.path.dirname(output_path), exist_ok=True)
        # Set output path
        bpy.context.scene.render.filepath = output_path
        
    def render_animation(self):
        bpy.ops.render.render(animation=True)
        
    def apply_effects(self, logo_object, effects_config):
        effects = effects_config.get("effects", [])
        for effect in effects:
            effect_type = effect.get("effect_type", "none")
            duration = effect.get("duration_frames", 60)
            parameters = effect.get("parameters", {})
            if effect_type == "none":
                continue  # Skip if no effect
            
            try:
                # Dynamically import the effect module
                effect_module = importlib.import_module(effect_type)
                # Apply the effect
                effect_module.apply_effect(logo_object, parameters, duration)
                print(f"Applied effect: {effect_type}")
            except ModuleNotFoundError:
                print(f"Effect module '{effect_type}' not found in effects directory.")
            except AttributeError:
                print(f"Effect module '{effect_type}' does not have an 'apply_effect' function.")
            except Exception as e:
                print(f"An error occurred while applying effect '{effect_type}': {e}")
                    
def main():
    project_dir = r"/mnt/c/Users/Jeff/logo"
    animator = LogoAnimator(project_dir)
    
    # Setup scene
    animator.setup_scene()
    
    # Create logo plane
    logo_obj = animator.create_logo_plane()
    
    # Load and apply effects from config
    try:
        config = animator.load_config()
        animator.apply_effects(logo_obj, config)
    except FileNotFoundError:
        print("No config.json found. Creating basic setup only.")
    
    # Setup output
    output_path = os.path.join(project_dir, "output", "animation", "animation")
    animator.setup_output(output_path)
    
    # Render
    animator.render_animation()

if __name__ == "__main__":
    main()