xDroid's Blog

为什么要折腾开机动画

我觉得要好好思考这个问题。

前天突发奇想,如果能把watchdog开机动画从手机移植到电脑上去就好了……于是我就去找了一下如何在Ubuntu上面实现开机动画,搜到Plymouth这个模块。

Arch Linux上面有一些对于这个模块的简介;不过没有Ubuntu Wiki上面这篇详细。先前走了不少弯路,没能正确预览动画;后来仔细读了一下教程,发现用plymouth-x11这个包的话就可以在图形界面下预览开机动画了。

主要的涉及到的步骤有这些:

  1. 安装plymouth-x11

    sudo apt-get install plymouth-x11```
    
    2.  预览动画:先开一个终端负责启动`plymouthd`
    ```bash
    sudo plymouthd --debug --tty=`tty` --no-daemon

    然后再开一个终端预览

    sudo plymouth show-splash
    sudo plymouth quit    #exit command
  2. 把现在可用的文件复制一份出来,并且设置默认项:

    mkdir ~/bootanim
    sudo cp /lib/plymouth/themes/ubuntu-logo ~/bootanim/myanim -R
    sudo cp /lib/plymouth/themes/default.plymouth ~/bootanim/myanim.plymouth
    sudo chown yourusername:youusername ~/bootanim -R
    sudo ln -s ~/bootanim/myanim.plymouth /lib/plymouth/themes/myanim.plymouth
    sudo ln -s ~/bootanim/myanim /lib/plymouth/themes/myanim
    sudo update-alternatives --install /lib/plymouth/themes/default.plymouth default.plymouth /lib/plymouth/themes/myanim.plymouth 101
    sudo update-alternatives --config default.plymouth   #and choose your anim
  3. 开始折腾拷贝出来的文件吧!!!期间犯了几次傻……

    fun num_to_longnum (int num) {...} //no 'int'
    parts = 4; num[parts] = [33, 62, 56, 58]; //should write into 'num = [...]'
    cyc = false; //no 'false'; use 0 instead

    语法蛮像js的,可参考:Scripts

  4. 顺便附上我在用的脚本:

    /*-----functions-----*/
    fun num_to_longnum (num) {
        if (num < 10)
            longnum = "0000" + num;
        else
            longnum = "000" + num;
        return longnum;
    }
    /*-----end of functions-----*/
    
    /*-----init-----*/
    time = 0;
    now_part.left = 3;
    now_part.main = 0;
    now_part.right = 5;
    now_index.left = 0;
    now_index.main = 0;
    now_index.right = 0;
    cyc = 0;
    end = 0;
    pro = 0;
    /*-----end of init-----*/
    
    /*-----consts-----*/
    maxopa = 0.5;
    parts = 7;
    //num = [1, 62, 56, 58, 62, 95, 53];
    num = [1, 1, 1, 58, 62, 95, 53];
    winwidth = Window.GetWidth();
    winheight = Window.GetHeight();
    picwidth = 460;
    picheight = 768;
    whiteheight = 50;
    fps = 50;
    /*-----end of consts-----*/
    
    /*-----load pics-----*/
    fun load_startup () {
        for (i = 0; i < parts; ++i) {
            for (j = 0; j < num[i]; ++j) {
                global.bg[i][j] = Image ("part" + i + "/" + num_to_longnum(j) + ".png");
            }
        }
        global.on = Image ("on.png");
        global.off = Image ("off.png");
        global.white = Image ("white.png");
    }
    
    fun load_shutdown () {
        for (j = 0; j < num[6]; ++j) {
            global.bg[6][j] = Image ("part" + i + "/" + num_to_longnum(j) + ".png");
        }
    }
    
    fun load () {
        if (Plymouth.GetMode () == "boot") {
            load_startup();
        } else if (Plymouth.GetMode() == "shutdown") {
            load_shutdown();
        }
    }
    /*-----end of load pics-----*/
    
    /*-----init-----*/
    fun init_startup () {
        global.main_sprite = Sprite();
        main_sprite.SetPosition (winwidth / 2 - picwidth / 2, winheight/2-picheight/2, -10);
    
        global.left_sprite = Sprite();
        left_sprite.SetPosition (winwidth / 2 - 3 * picwidth / 2, winheight/2-picheight/2, -15);
    
        global.right_sprite = Sprite();
        right_sprite.SetPosition (winwidth / 2 + picwidth / 2, winheight/2-picheight/2, -15);
    
        global.white_sprite = Sprite();
        white_sprite.SetImage (white);
        white_sprite.SetOpacity (0.5);
    }
    
    fun init_shutdown () {
        global.main_sprite = Sprite();
        main_sprite.SetPosition (winwidth / 2 - picwidth / 2, winheight/2-picheight/2, -10);
    }
    
    fun init () {
        if (Plymouth.GetMode () == "boot") {
            init_startup();
        } else if (Plymouth.GetMode() == "shutdown") {
            init_shutdown();
        }
    }
    /*-----end of init-----*/
    
    /*-----main-----*/
    fun refresh_callback_startup () {
        /*info_text = Image.Text ("Waited " + time / 50 + " seconds");
        info_sprite = Sprite (info_text);
        info_sprite.SetX (Window.GetWidth ()  / 2 - info_sprite.GetImage().GetWidth()  / 2);
        info_sprite.SetY (Window.GetHeight () / 3);
        info_sprite.SetZ (-5);*/
    
        if (!cyc) {
            main_sprite.SetImage (bg[now_part.main][now_index.main]);
        } else {
            if (time % 100 < 90) main_sprite.SetImage (off); else main_sprite.SetImage (on); main_sprite.SetOpacity (main_sprite.GetOpacity() * 0.01 + 100 * 0.99); } if (now_part.main > now_part.left) {
            left_sprite.SetImage(bg[now_part.left][now_index.left]);
            left_sprite.SetOpacity(maxopa * Math.Abs(Math.Sin(Math.Pi * now_index.left / num[now_part.left])));
        }
    
        if (now_part.main > now_part.right) {
            right_sprite.SetImage(bg[now_part.right][now_index.right]);
            right_sprite.SetOpacity(maxopa * Math.Abs(Math.Sin(Math.Pi * now_index.right / num[now_part.right])));
        }
    
        white_sprite.SetPosition(pro * winwidth - winwidth, winheight - whiteheight, -5);
    
        time++;
        if (time % 2 == 0) {
            if (!cyc) {
                now_index.main++;
                if (now_index.main == num[now_part.main]) {
                    now_index.main = 0;
                    now_part.main++;
                    if (now_part.main == parts) {
                        now_part.main = parts - 1;
                        cyc = 1;
                        main_sprite.SetOpacity(0);
                    }
                }
            }
            now_index.left++;
            if (now_index.left == num[now_part.left])
                now_index.left = 0;
    
            now_index.right++;
            if (now_index.right == num[now_part.right])
                now_index.right = 0;
    
        }
    }
    
    fun refresh_callback_shutdown () {
        now_part.main = 6;
        if (!end) {
            main_sprite.SetImage (bg[now_part.main][num[now_part.main] - now_index.main - 1]);
        }
    
        time++;
        if (time % 5 == 0) {
            if (!end) {
                now_index.main++;
                if (now_index.main == num[now_part.main]) {
                    end = 1;
                    main_sprite.SetOpacity(0);
                }
            }
        }
    }
    
    fun refresh_callback() {
        if (Plymouth.GetMode () == "boot") {
            refresh_callback_startup();
        } else if (Plymouth.GetMode() == "shutdown") {
            refresh_callback_shutdown();
        }
    }
    load();
    init();
    Plymouth.SetRefreshFunction (refresh_callback);
    /*-----end of main-----*/
    
    fun progress_callback (time, progress) {
        pro = progress;
    }
    Plymouth.SetBootProgressFunction (progress_callback);