#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Panda3D 视频播放示例
演示如何在Panda3D中播放内嵌视频
"""

from direct.showbase.ShowBase import ShowBase
from panda3d.core import (
    MovieTexture, CardMaker, TextureStage, NodePath,
    WindowProperties, loadPrcFileData, Vec3, Point3,
    AmbientLight, DirectionalLight, GeomNode
)
import os

# 配置Panda3D
loadPrcFileData("", """
    win-size 1280 720
    window-title Panda3D 视频播放器
    show-frame-rate-meter true
""")

class VideoPlayerDemo(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        # 设置背景色
        self.setBackgroundColor(0.1, 0.1, 0.1)
        
        # 设置相机
        self.cam.setPos(0, -10, 0)
        self.cam.lookAt(0, 0, 0)
        
        # 添加光照
        self.setup_lighting()
        
        # 创建视频播放器
        self.setup_video_players()
        
        # 设置控制
        self.setup_controls()
        
        print("视频播放器已启动!")
        print("控制键:")
        print("  SPACE - 播放/暂停")
        print("  R - 重新播放")
        print("  + - 加速播放")
        print("  - - 减速播放")
        print("  ESC - 退出")
        
    def setup_lighting(self):
        """设置基础光照"""
        # 环境光
        alight = AmbientLight('ambient')
        alight.setColor((0.3, 0.3, 0.3, 1))
        alnp = self.render.attachNewNode(alight)
        self.render.setLight(alnp)
        
        # 定向光
        dlight = DirectionalLight('directional')
        dlight.setColor((0.8, 0.8, 0.8, 1))
        dlnp = self.render.attachNewNode(dlight)
        dlnp.setHpr(45, -45, 0)
        self.render.setLight(dlnp)
    
    def setup_video_players(self):
        """设置视频播放器"""
        self.videos = []
        
        # 方法1: 平面视频播放器
        self.create_flat_video_player()
        
        # 方法2: 3D模型上的视频纹理
        self.create_3d_video_screen()
        
        # 方法3: 球形全景视频
        self.create_spherical_video()
    
    def create_flat_video_player(self):
        """创建平面视频播放器"""
        try:
            # 创建视频纹理 (这里使用示例路径，需要替换为实际视频文件)
            video_path = "video/sample.mp4"  # 支持 .mp4, .avi, .mov 等格式
            
            # 如果文件不存在，创建一个简单的色彩动画作为演示
            if not os.path.exists(video_path):
                self.create_color_animation_demo()
                return
            
            # 加载视频
            movie_texture = MovieTexture()
            success = movie_texture.read(video_path)
            
            if success:
                # 创建卡片几何体
                cm = CardMaker("video_card")
                cm.setFrame(-2, 2, -1.5, 1.5)
                
                video_card = self.render.attachNewNode(cm.generate())
                video_card.setTexture(movie_texture)
                video_card.setPos(-4, 0, 0)
                
                # 播放视频
                movie_texture.play()
                
                self.videos.append({
                    'texture': movie_texture,
                    'node': video_card,
                    'name': 'flat_video'
                })
                
                print(f"✓ 平面视频播放器创建成功: {video_path}")
            else:
                print(f"✗ 无法加载视频: {video_path}")
                
        except Exception as e:
            print(f"创建平面视频播放器失败: {str(e)}")
    
    def create_3d_video_screen(self):
        """在3D模型上创建视频纹理"""
        try:
            # 创建一个简单的立方体作为"电视屏幕"
            from panda3d.core import CardMaker
            
            # 创建屏幕边框
            frame_cm = CardMaker("screen_frame")
            frame_cm.setFrame(-2.2, 2.2, -1.7, 1.7)
            screen_frame = self.render.attachNewNode(frame_cm.generate())
            screen_frame.setColor(0.1, 0.1, 0.1, 1)
            screen_frame.setPos(0, 0, 0)
            
            # 创建屏幕
            screen_cm = CardMaker("video_screen")
            screen_cm.setFrame(-2, 2, -1.5, 1.5)
            video_screen = screen_frame.attachNewNode(screen_cm.generate())
            
            # 创建程序化视频内容 (颜色渐变动画)
            movie_texture = self.create_procedural_video(panoramic=False)
            video_screen.setTexture(movie_texture)
            
            self.videos.append({
                'texture': movie_texture,
                'node': video_screen,
                'name': '3d_screen'
            })
            
            print("✓ 3D视频屏幕创建成功")
            
        except Exception as e:
            print(f"创建3D视频屏幕失败: {str(e)}")
    
    def create_spherical_video(self):
        """创建球形全景视频"""
        try:
            # 创建球体几何（程序化生成）
            sphere = self.create_sphere_geometry(radius=2)
            sphere.reparentTo(self.render)
            sphere.setPos(4, 0, 0)
            sphere.setScale(2)
            
            # 反转法线以便从内部观看
            sphere.setTwoSided(True)
            
            # 创建全景视频纹理
            panoramic_texture = self.create_procedural_video(panoramic=True)
            sphere.setTexture(panoramic_texture)
            
            self.videos.append({
                'texture': panoramic_texture,
                'node': sphere,
                'name': 'spherical_video'
            })
            
            print("✓ 球形全景视频创建成功")
            
        except Exception as e:
            print(f"创建球形全景视频失败: {str(e)}")
    
    def create_sphere_geometry(self, radius=1):
        """程序化创建球体几何"""
        # 创建简化的球体（立方体的6个面）
        sphere_root = self.render.attachNewNode("sphere")
        
        faces = [
            # (位置, 旋转)
            (Vec3(0, radius, 0), Vec3(0, 0, 0)),      # 前面
            (Vec3(0, -radius, 0), Vec3(0, 180, 0)),   # 后面
            (Vec3(radius, 0, 0), Vec3(0, 90, 0)),     # 右面
            (Vec3(-radius, 0, 0), Vec3(0, -90, 0)),   # 左面
            (Vec3(0, 0, radius), Vec3(-90, 0, 0)),    # 上面
            (Vec3(0, 0, -radius), Vec3(90, 0, 0)),    # 下面
        ]
        
        cm = CardMaker("sphere_face")
        cm.setFrame(-radius, radius, -radius, radius)
        
        for i, (pos, hpr) in enumerate(faces):
            face = sphere_root.attachNewNode(cm.generate())
            face.setPos(pos)
            face.setHpr(hpr)
        
        return sphere_root
    
    def create_procedural_video(self, panoramic=False):
        """创建程序化视频内容作为演示"""
        from panda3d.core import PNMImage, Texture
        
        # 创建动态纹理
        texture = Texture()
        if panoramic:
            texture.setup2dTexture(512, 256, Texture.TUnsignedByte, Texture.FRgba)
        else:
            texture.setup2dTexture(256, 256, Texture.TUnsignedByte, Texture.FRgba)
        
        # 启动更新任务 - 修复参数传递使用lambda
        task_name = f"update_video_{'panoramic' if panoramic else 'normal'}"
        self.taskMgr.add(lambda task: self.update_procedural_video(task, texture, panoramic), task_name)
        
        return texture
    
    def update_procedural_video(self, task, texture, panoramic):
        """更新程序化视频内容"""
        try:
            from panda3d.core import PNMImage
            import math
            
            # 获取当前时间
            time = task.time
            
            # 根据纹理类型创建不同尺寸的图像
            if panoramic:
                img = PNMImage(512, 256, 4)  # 全景纹理
                width, height = 512, 256
            else:
                img = PNMImage(256, 256, 4)  # 普通纹理
                width, height = 256, 256
            
            for y in range(height):
                for x in range(width):
                    # 创建动态色彩效果
                    if panoramic:
                        # 全景模式：创建旋转的渐变
                        u = x / float(width)  # 经度 (0-1)
                        v = y / float(height)  # 纬度 (0-1)
                        
                        angle = u * 2 * math.pi + time * 0.5
                        height_factor = (v - 0.5) * math.pi
                        
                        r = (math.sin(angle * 3) + 1) * 0.5
                        g = (math.cos(angle * 2 + height_factor * 4) + 1) * 0.5
                        b = (math.sin(height_factor * 6 + time) + 1) * 0.5
                    else:
                        # 普通模式：创建波纹效果
                        center_x = width // 2
                        center_y = height // 2
                        dist_x = (x - center_x) / float(center_x)
                        dist_y = (y - center_y) / float(center_y)
                        distance = math.sqrt(dist_x**2 + dist_y**2)
                        
                        wave = math.sin(distance * 10 - time * 5)
                        r = (wave + 1) * 0.5
                        g = (math.sin(dist_x * 5 + time * 2) + 1) * 0.5
                        b = (math.sin(dist_y * 5 + time * 3) + 1) * 0.5
                    
                    img.setXel(x, y, r, g, b)
                    img.setAlpha(x, y, 1.0)
            
            # 更新纹理
            texture.load(img)
            
            return task.cont
            
        except Exception as e:
            print(f"更新程序化视频失败: {str(e)}")
            return task.done
    
    def create_color_animation_demo(self):
        """创建颜色动画演示（当没有视频文件时）"""
        try:
            # 创建卡片
            cm = CardMaker("color_demo")
            cm.setFrame(-2, 2, -1.5, 1.5)
            
            demo_card = self.render.attachNewNode(cm.generate())
            demo_card.setPos(-4, 0, 0)
            
            # 创建动态颜色纹理
            demo_texture = self.create_procedural_video(panoramic=False)
            demo_card.setTexture(demo_texture)
            
            self.videos.append({
                'texture': demo_texture,
                'node': demo_card,
                'name': 'color_demo'
            })
            
            print("✓ 颜色动画演示创建成功")
            
        except Exception as e:
            print(f"创建颜色动画演示失败: {str(e)}")
    
    def setup_controls(self):
        """设置控制键"""
        self.accept("space", self.toggle_play_pause)
        self.accept("r", self.restart_videos)
        self.accept("plus", self.speed_up)
        self.accept("minus", self.slow_down)
        self.accept("escape", self.quit_app)
        
        # 鼠标控制相机
        self.accept("mouse1", self.start_camera_rotation)
        self.accept("mouse1-up", self.stop_camera_rotation)
        
        self.camera_rotating = False
        self.last_mouse_x = 0
        self.last_mouse_y = 0
        
        # 启动相机更新任务
        self.taskMgr.add(self.update_camera_rotation, "camera_rotation")
    
    def toggle_play_pause(self):
        """切换播放/暂停"""
        for video in self.videos:
            if hasattr(video['texture'], 'isPlaying'):
                if video['texture'].isPlaying():
                    video['texture'].stop()
                    print(f"暂停视频: {video['name']}")
                else:
                    video['texture'].play()
                    print(f"播放视频: {video['name']}")
    
    def restart_videos(self):
        """重新播放所有视频"""
        for video in self.videos:
            if hasattr(video['texture'], 'play'):
                video['texture'].setTime(0)
                video['texture'].play()
                print(f"重新播放视频: {video['name']}")
    
    def speed_up(self):
        """加速播放"""
        for video in self.videos:
            if hasattr(video['texture'], 'getPlayRate'):
                current_rate = video['texture'].getPlayRate()
                new_rate = min(current_rate * 1.5, 4.0)
                video['texture'].setPlayRate(new_rate)
                print(f"加速播放 {video['name']}: {new_rate:.2f}x")
    
    def slow_down(self):
        """减速播放"""
        for video in self.videos:
            if hasattr(video['texture'], 'getPlayRate'):
                current_rate = video['texture'].getPlayRate()
                new_rate = max(current_rate / 1.5, 0.25)
                video['texture'].setPlayRate(new_rate)
                print(f"减速播放 {video['name']}: {new_rate:.2f}x")
    
    def start_camera_rotation(self):
        """开始相机旋转"""
        if self.mouseWatcherNode.hasMouse():
            self.camera_rotating = True
            self.last_mouse_x = self.mouseWatcherNode.getMouseX()
            self.last_mouse_y = self.mouseWatcherNode.getMouseY()
    
    def stop_camera_rotation(self):
        """停止相机旋转"""
        self.camera_rotating = False
    
    def update_camera_rotation(self, task):
        """更新相机旋转"""
        if self.camera_rotating and self.mouseWatcherNode.hasMouse():
            mouse_x = self.mouseWatcherNode.getMouseX()
            mouse_y = self.mouseWatcherNode.getMouseY()
            
            delta_x = mouse_x - self.last_mouse_x
            delta_y = mouse_y - self.last_mouse_y
            
            # 更新相机方向
            self.cam.setH(self.cam.getH() - delta_x * 50)
            new_p = self.cam.getP() + delta_y * 50
            self.cam.setP(max(min(new_p, 89), -89))
            
            self.last_mouse_x = mouse_x
            self.last_mouse_y = mouse_y
        
        return task.cont
    
    def quit_app(self):
        """退出应用"""
        print("退出视频播放器...")
        self.userExit()

if __name__ == "__main__":
    app = VideoPlayerDemo()
    app.run() 