%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% media9.sty
%
% multimedia inclusion package
%
% Copyright 2012--\today, Alexander Grahn
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% This package implements Adobe-Reader 9 and X compatible RichMedia
% annotation for multimedia (Flash & 3D) inclusion according to:
%
% Adobe Supplement to ISO 32000, BaseVersion 1.7, ExtensionLevel 3
%
% Supported workflows:
%
%   pdflatex, lualatex
%   latex-->dvips-->ps2pdf or Distiller
%   latex-->dvipdfmx
%   xelatex
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License.
%
% The latest version of this license is in
%   http://mirrors.ctan.org/macros/latex/base/lppl.txt
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is A. Grahn.

\RequirePackage{expl3}
\RequirePackage{l3keys2e}
\RequirePackage{xparse}
\RequirePackage{atbegshi}

\def\g@mix@date@tl{2019/02/21}
\def\g@mix@version@tl{0.96}

\def\g@mix@liiikerneldate{2019/02/15}
\def\g@mix@liiipkgdate{2018/10/17}

\ProvidesExplPackage{media9}{\g@mix@date@tl}{\g@mix@version@tl}
{acrobat-9/X compatible media}

\tl_gset_eq:NN\g_mix_date_tl\g@mix@date@tl
\tl_gset_eq:NN\g_mix_version_tl\g@mix@version@tl

\cs_if_exist:NTF\msg_set:nnnn{
  \msg_set:nnnn{media9}{support~outdated}{
    Support~package~#1~too~old.
  }{
    Please~install~an~up~to~date~version~of~#1.\\
    Loading~media9~will~abort!
  }
}{
  \PackageError{media9}{Support~package~expl3~too~old.}{
      Please~install~an~up~to~date~version~of~expl3.\\
      Loading~media9~will~abort!
  }
  \tex_endinput:D
}
\@ifpackagelater{expl3}{\g@mix@liiikerneldate}{}{
  \msg_error:nnn{media9}{support~outdated}{l3kernel}
  \tex_endinput:D
}
\@ifpackagelater{xparse}{\g@mix@liiipkgdate}{}{
  \msg_error:nnn{media9}{support~outdated}{l3packages}
  \tex_endinput:D
}
\@ifpackagelater{l3keys2e}{\g@mix@liiipkgdate}{}{
  \msg_error:nnn{media9}{support~outdated}{l3packages}
  \tex_endinput:D
}

%package options

%unknown package option error message
\msg_set:nnnn{media9}{unknown~package~option}{Unknown~package~option~`#1'.}{
  Package option~'#1'~is~unknown;\\
  perhaps~it~is~spelled~incorrectly.
}

\bool_new:N\g_mix_pkgattach_bool
\bool_new:N\g_mix_dvipdfmx_bool
\bool_new:N\g_mix_pkgdraft_bool
\bool_new:N\g_mix_opt_pkgwindowed_bool
\int_new:N\g_mix_pkgresizeflag_int% resizing flag according to options given
\tl_gset:Nn\g_mix_pkgwdarg_tl{\width}
\tl_gset:Nn\g_mix_pkghtarg_tl{\height}
\tl_gset:Nn\g_mix_pkgttarg_tl{\totalheight}
\bool_new:N\g_mix_pkgiso_bool
\tl_gset:Nn\g_mix_pkgscalearg_tl{1.0}
\tl_gset:Nx\g_mix_pkgwinsize_tl{defaultxdefault}
\tl_gset:Nx\g_mix_pkgwinpos_tl{cc}
\tl_gset:Nn\g_mix_pkgact_tl{/XA}
\tl_gset:Nn\g_mix_pkgdeact_tl{/PC}
\tl_gset:Nn\g_mix_pkgtransp_tl{false}
\tl_gset:Nn\g_mix_pkgcontextclick_tl{false}
\tl_gset:Nn\g_mix_pkgplaycnt_tl{-1}
\tl_gset:Nn\g_mix_pkgplayspd_tl{1}
\tl_gset:Nn\g_mix_pkgplaytpe_tl{None}
\tl_gset:Nn\g_mix_pkgtools_tl{false}
\tl_gset:Nn\g_mix_pkgnrdflt_tl{/NR~true}
\tl_gset:Nn\g_mix_pkgnav_tl{false}
\tl_gclear:N\g_mix_pkgopt_bg_tl
\tl_gclear:N\g_mix_pkgopt_ls_tl
\tl_gclear:N\g_mix_pkgopt_rm_tl
\bool_new:N\g_mix_pkgiiidcalc_bool
\tl_gset:Nn\g_mix_pkgpbtn_tl{fancy}

%floating window settings
\group_begin:
\char_set_catcode_other:n{`\@}
\cs_new_protected:Npn\mix_parse_windowedarg:w#1@#2@#3\q_stop{
  \tl_if_blank:nF{#1}{\tl_gset:Nn\g_mix_winsize_tl{#1}}
  \tl_if_blank:nF{#2}{\tl_gset:Nn\g_mix_winpos_tl{#2}}
}
\cs_new_protected:Nn\mix_parse_windowedarg:N{
  \exp_after:wN\mix_parse_windowedarg:w#1@@\q_stop
}
\group_end:

\cs_new:Npn\mix_parse_winsizearg:w#1x#2\q_stop{
  \str_if_eq:nnTF{#1}{default}{
    \tl_gset:Nx\tl_mix_fltwd{
      \fp_to_int:n{1.522*\dim_to_decimal_in_bp:n{\g_mix_wd_tl}}}
    \tl_gset:Nx\tl_mix_fltht{
      \fp_to_int:n{1.522*\dim_to_decimal_in_bp:n{\g_mix_tt_tl}}}
  }{
    \tl_gset:Nn\tl_mix_fltwd{#1}
    \tl_gset:Nn\tl_mix_fltht{#2}
  }
}

\keys_define:nn{media9}{
  xetex .code:n = {
    \PassOptionsToPackage{xetex}{pdfbase}
  },

  dvipdfmx .code:n = {
    \PassOptionsToPackage{dvipdfmx}{pdfbase}
    \bool_gset_true:N\g_mix_dvipdfmx_bool
  },

  bigfiles .choice:,
  bigfiles / true .code:n = {
    \@ifpackageloaded{pdfbase}{
      \bool_gset_true:N\g_pbs_pkgbigfiles_bool
    }{
      \PassOptionsToPackage{bigfiles}{pdfbase}
    }
  },
  bigfiles / false .code:n = {},
  bigfiles .default:n = {true},

  draft .choice:,
  draft / true .code:n = {\bool_gset_true:N\g_mix_pkgdraft_bool},
  draft / false .code:n = {\bool_gset_false:N\g_mix_pkgdraft_bool},
  draft .default:n = {true},

  final .choice:,
  final / true .code:n = {\bool_gset_false:N\g_mix_pkgdraft_bool},
  final / false .code:n = {\bool_gset_true:N\g_mix_pkgdraft_bool},
  final .default:n = {true},

  attachfiles .choice:,
  attachfiles / true .code:n = {\bool_gset_true:N\g_mix_pkgattach_bool},
  attachfiles / false .code:n = {\bool_gset_false:N\g_mix_pkgattach_bool},
  attachfiles .default:n = {true},

  noplaybutton .choice:,
  noplaybutton / true .code:n = {\tl_gset:Nn\g_mix_pkgpbtn_tl{none}},
  noplaybutton .default:n = {true},

  playbutton .choice:,
  playbutton / fancy .code:n = {\tl_gset:Nn\g_mix_pkgpbtn_tl{fancy}},
  playbutton / plain .code:n = {\tl_gset:Nn\g_mix_pkgpbtn_tl{plain}},
  playbutton / none .code:n = {\tl_gset:Nn\g_mix_pkgpbtn_tl{none}},
  playbutton .default:n = {fancy},

  activate .choice:,
  activate / pagevisible .code:n = {\tl_gset:Nn\g_mix_pkgact_tl{/PV}},
  activate / pageopen .code:n = {\tl_gset:Nn\g_mix_pkgact_tl{/PO}},
  activate / onclick .code:n = {\tl_gset:Nn\g_mix_pkgact_tl{/XA}},
  activate .value_required:n = {true},

  deactivate .choice:,
  deactivate / pageinvisible .code:n = {\tl_gset:Nn\g_mix_pkgdeact_tl{/PI}},
  deactivate / pageclose .code:n = {\tl_gset:Nn\g_mix_pkgdeact_tl{/PC}},
  deactivate / onclick .code:n = {\tl_gset:Nn\g_mix_pkgdeact_tl{/XD}},
  deactivate .value_required:n = {true},

  transparent .choices:nn = {true,false}{
    \tl_gset:Nx\g_mix_pkgtransp_tl{\l_keys_choice_tl}
  },
  transparent .default:n = {true},

  passcontext .choices:nn = {true,false}{
    \tl_gset:Nx\g_mix_pkgcontextclick_tl{\l_keys_choice_tl}
  },
  passcontext .default:n = {true},

  windowed .code:n = {
    \str_if_eq:nnTF{#1}{false}{
      \bool_gset_false:N\g_mix_opt_pkgwindowed_bool
    }{
      \bool_gset_true:N\g_mix_opt_pkgwindowed_bool
      \tl_set:Nx\l_tmpa_tl{#1}
      \tl_remove_all:Nn\l_tmpa_tl{~}
      \mix_parse_windowedarg:N\l_tmpa_tl
      \tl_gset_eq:NN\g_mix_pkgwinsize_tl\g_mix_winsize_tl
      \tl_gset_eq:NN\g_mix_pkgwinpos_tl\g_mix_winpos_tl
    }
  },

  width .code:n = {
    \tl_gset:Nn\g_mix_pkgwdarg_tl{#1}
    \tl_if_exist:NF\l_mix_pkgwd_tl{
      \int_gadd:Nn\g_mix_pkgresizeflag_int{\c_four}
      \tl_set:Nn\l_mix_pkgwd_tl{}
    }
  },
  width .value_required:n = {true},

  height .code:n = {
    \tl_gset:Nn\g_mix_pkghtarg_tl{#1}
    \tl_if_exist:NF\l_mix_pkght_tl{
      \int_gadd:Nn\g_mix_pkgresizeflag_int{\c_two}
      \tl_set:Nn\l_mix_pkght_tl{}
    }
  },
  height .value_required:n = {true},

  totalheight .code:n = {
    \tl_gset:Nn\g_mix_pkgttarg_tl{#1}
    \tl_if_exist:NF\l_mix_pkgtt_tl{
      \int_gadd:Nn\g_mix_pkgresizeflag_int{\c_one}
      \tl_set:Nn\l_mix_pkgtt_tl{}
    }
  },
  height .value_required:n = {true},

  depth .code:n = {
    \msg_warning:nnnn{media9}{deprecated~option}{depth}{
      Ignoring~`depth'~option.
    }
  },

  keepaspectratio .choice:,
  keepaspectratio / true .code:n = {\bool_gset_true:N\g_mix_pkgiso_bool},
  keepaspectratio / false .code:n = {\bool_gset_false:N\g_mix_pkgiso_bool},
  keepaspectratio .default:n = {true},

  scale .code:n = {\tl_gset:Nx\g_mix_pkgscalearg_tl{#1}},
  scale .value_required:n = {true},

  %3D specific options
  3Dplaytype .choice:,
  3Dplaytype / none .code:n = {\tl_gset:Nn\g_mix_pkgplaytpe_tl{None}},
  3Dplaytype / linear .code:n = {\tl_gset:Nn\g_mix_pkgplaytpe_tl{Linear}},
  3Dplaytype / oscillating .code:n = {
    \tl_gset:Nn\g_mix_pkgplaytpe_tl{Oscillating}},
  3Dplaytype .value_required:n = {true},

  3Dplaycount .code:n = {\tl_gset:Nx\g_mix_pkgplaycnt_tl{\fp_eval:n{trunc(#1)}}},
  3Dplaycount .value_required:n = {true},

  3Dplayspeed .tl_gset_x:N = \g_mix_pkgplayspd_tl,
  3Dplayspeed .value_required:n = {true},

  3Dtoolbar .choices:nn = {true,false}{
    \tl_gset:Nx\g_mix_pkgtools_tl{\l_keys_choice_tl}
  },
  3Dtoolbar .default:n = {true},

  3Dnavpane .choices:nn = {true,false}{
    \tl_gset:Nx\g_mix_pkgnav_tl{\l_keys_choice_tl}
  },
  3Dnavpane .default:n = {true},

  3Dpartsattrs .choices:nn = {keep,restore}{
    \tl_set:Nn\l_mix_keep_tl{keep}
    \tl_if_eq:NNTF\l_keys_choice_tl\l_mix_keep_tl{
      \tl_gset:Nn\g_mix_pkgnrdflt_tl{/NR~false}
    }{
      \tl_gset:Nn\g_mix_pkgnrdflt_tl{/NR~true}
    }
  },
  3Dpartsattrs .value_required:n = {true},

  3Dmenu .bool_gset:N = \g_mix_pkgiiidcalc_bool,

  3Dbg .code:n = {
    \tl_gset:Nx\g_mix_pkgopt_bg_tl{
      /BG<</Subtype/SC/CS/DeviceRGB/C[#1]/EA~true>>}
  },
  3Dbg .value_required:n = {true},

  3Dlights .code:n = {
    \tl_gset:Nx\g_mix_pkgopt_ls_tl{/LS<</Subtype/#1>>}
  },
  3Dlights .value_required:n = {true},

  3Drender .code:n = {
    \tl_gset:Nx\g_mix_pkgopt_rm_tl{/RM<</Subtype/#1>>}
  },
  3Drender .value_required:n = {true},

  unknown .code:n = {
    \msg_error:nnx{media9}{unknown~package~option}{\l_keys_key_tl}
  }
}
\ProcessKeysOptions{media9}
\sys_if_engine_xetex:T{\bool_gset_true:N\g_mix_dvipdfmx_bool}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage{pdfbase}
%aliases for commands from pdfbase.sty
\cs_set_eq:NN\mix_pdfobj:nnn   \pbs_pdfobj:nnn
\cs_set_eq:NN\mix_pdfannot:nnnn\pbs_pdfannot:nnnn
\cs_set_eq:NN\mix_appendtofields:n\pbs_appendtofields:n
\cs_set_eq:NN\mix_pdflink:nn   \pbs_pdflink:nn
\cs_new:Nn\mix_pdfxform:n{\pbs_pdfxform:nnnnn{1}{1}{}{}{#1}}
\cs_set_eq:NN\mix_pdfximage:n  \pbs_pdfximage:n
\cs_set_eq:NN\mix_pdfcatalog:n \pbs_pdfcatalog:n

\cs_set_eq:NN\mix_pdflastobj:   \pbs_pdflastobj:
\cs_set_eq:NN\mix_pdflastann:   \pbs_pdflastann:
\cs_set_eq:NN\mix_pdflastxform: \pbs_pdflastxform:
\cs_set_eq:NN\mix_pdflastximage:\pbs_pdflastximage:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage{ocgbase} %OCG generating and configuration macros

\box_new:N\l_mix_poster_box
\dim_new:N\g_mix_wd_dim
\dim_new:N\g_mix_ht_dim
\dim_new:N\g_mix_dp_dim

\int_new:N\g_mix_rmcnt_int
\int_new:N\l_mix_viewcnt_int %counter for 3D views per annot

\int_new:N\g@mix@page@int %abs. page counter (zero based)
\int_gset:Nn\g@mix@page@int{-1}
\AtBeginShipout{\int_gincr:N\g@mix@page@int}

\bool_new:N\l_mix_url_bool
\bool_new:N\g_mix_iiidcalc_bool

%missing package error message
%example usage:
%  \msg_error:nnnn{media9}{missing~package}{graphicx}{[dvipdfmx]}
%  \msg_error:nnn{media9}{missing~package}{graphicx}
\msg_set:nnn{media9}{missing~package}{
  Package~`#1'~has~not~been~loaded~yet.\\
  Put~the~line\\
  ~~\string\usepackage#2{#1}\\
  to~the~preamble~of~your~document.
}

%file not found error message
%example usage:
%  \msg_error:nnn{media9}{file~not~found}{myfile.swf}
\msg_set:nnnn{media9}{file~not~found}{
  Line~\msg_line_number: :~
  File~`#1'~not~found.}{Make~sure~file~`#1'~exists~and~is~readable!}

\sys_if_engine_pdftex:TF{
  %\pdfmdfivesum is used for hashing object references of embedded files
  \cs_new:Nn\mix_filemdfivesum:n{\pdfmdfivesum~file~{#1}}
  \cs_new:Nn\mix_unescapehex:n{(\pdfunescapehex{#1})}
}{
  \sys_if_engine_luatex:TF{
    \RequirePackage{pdftexcmds}
    \cs_new_nopar:Nn\mix_filemdfivesum:n{\pdf@filemdfivesum{#1}}
    %\cs_new:Nn\mix_unescapehex:n{<#1>}
    \cs_new_nopar:Nn\mix_unescapehex:n{(\pdf@unescapehex{#1})}
  }{
    \cs_if_exist:NTF\mdfivesum{
      \cs_new_nopar:Nn\mix_filemdfivesum:n{\mdfivesum file {#1}}
    }{
      \cs_new_nopar:Nn\mix_filemdfivesum:n{#1}
    }
  }
}

%creating global definitions
\cs_new:Npn\mix@newkey#1#2{\tl_gset:cx{#1}{#2}}
\AtBeginDocument{
  \iow_now:Nx\@mainaux{
    \token_to_str:N\providecommand\token_to_str:N\mix@newkey[2]{}}
}

%macros for writing global defs to \jobname.aux
\msg_set:nnn{media9}{rerun}{Rerun~to~get~internal~references~right!}
\msg_set:nnn{media9}{undefined~reference}{
  Line~\msg_line_number: :~Media~reference~`#1'~not~defined.
}
\msg_set:nnn{media9}{undefined~references}{
  There~were~undefined~media~references!}
\msg_set:nnn{media9}{same~label}{
  Line~\msg_line_number: :~Label~`#1'~multiply~defined.
}
\msg_set:nnn{media9}{multiple~labels}{There~were~multiply-defined~labels!}

\cs_new_nopar:Nn\mix_keytoaux_now:nn{
  \iow_now:Nx\@mainaux{\token_to_str:N\mix@newkey{#1}{#2}}
  \bool_if:nT{
    !\cs_if_exist:cTF{#1}{
      \str_if_eq_x_p:nn{\tl_use:c{#1}}{#2}
    }{
      \c_false_bool
    }
  }{
    \cs_if_exist:NF\g_mix_rerunwarned_tl{
      \tl_new:N\g_mix_rerunwarned_tl
      \AtEndDocument{\msg_warning:nn{media9}{rerun}}
    }
  }
}
\cs_new_nopar:Nn\mix_keytoaux_shipout:nn{
  \iow_shipout_x:Nx\@mainaux{\token_to_str:N\mix@newkey{#1}{#2}}
  \cs_if_exist:cF{#1}{
    \cs_if_exist:NF\g_mix_rerunwarned_tl{
      \tl_new:N\g_mix_rerunwarned_tl
      \AtEndDocument{\msg_warning:nn{media9}{rerun}}
    }
  }
}

%reset various variables for every new media inclusion
\cs_new:Nn\mix_reset:{
  \tl_gset:Nx\g_mix_label_tl{rm@\int_use:N\g_mix_rmcnt_int}
  \tl_gclear:N\g_mix_usrlabel_tl
  \tl_gclear:N\g_mix_flashvars_tl
  \tl_gclear:N\g_mix_assets_tl
  \tl_gclear:N\g_mix_configurations_tl
  \tl_gset_eq:NN\g_mix_act_tl\g_mix_pkgact_tl
  \tl_gset_eq:NN\g_mix_deact_tl\g_mix_pkgdeact_tl
  \box_clear:N\l_mix_poster_box
  \tl_clear:N\l_mix_scripts_tl
  \bool_gset_eq:NN\g_mix_usrdraft_bool\g_mix_pkgdraft_bool
  \bool_gset_eq:NN\g_mix_usrattach_bool\g_mix_pkgattach_bool
  \tl_gset_eq:NN\g_mix_usrpbtn_tl\g_mix_pkgpbtn_tl
  \seq_gclear:N\g_mix_res_seq
  \seq_gclear:N\g_mix_script_seq
  \int_gset_eq:NN\g_mix_resizeflag_int\g_mix_pkgresizeflag_int
  \tl_set_eq:NN\l_mix_usrwd_tl\l_mix_pkgwd_tl
  \tl_set_eq:NN\l_mix_usrht_tl\l_mix_pkght_tl
  \tl_set_eq:NN\l_mix_usrtt_tl\l_mix_pkgtt_tl
  \tl_gset_eq:NN\g_mix_wdarg_tl\g_mix_pkgwdarg_tl
  \tl_gset_eq:NN\g_mix_htarg_tl\g_mix_pkghtarg_tl
  \tl_gset_eq:NN\g_mix_ttarg_tl\g_mix_pkgttarg_tl
  \bool_gset_eq:NN\g_mix_usriso_bool\g_mix_pkgiso_bool
  \tl_gset_eq:NN\g_mix_scalearg_tl\g_mix_pkgscalearg_tl
  \tl_gset_eq:NN\g_mix_transp_tl\g_mix_pkgtransp_tl
  \tl_gset_eq:NN\g_mix_contextclick_tl\g_mix_pkgcontextclick_tl
  \bool_gset_eq:NN\g_mix_opt_windowed_bool\g_mix_opt_pkgwindowed_bool
  \tl_gset_eq:NN\g_mix_winsize_tl\g_mix_pkgwinsize_tl
  \tl_gset_eq:NN\g_mix_winpos_tl\g_mix_pkgwinpos_tl

  %3D specific settings
  \bool_gset_false:N\g_mix_iiid_bool
  \bool_gset_false:N\g_mix_opt_iiidview_bool
  \bool_gset_eq:NN\g_mix_iiidcalc_bool\g_mix_pkgiiidcalc_bool

  \tl_gset_eq:NN\g_mix_playcnt_tl\g_mix_pkgplaycnt_tl
  \tl_gset_eq:NN\g_mix_playspd_tl\g_mix_pkgplayspd_tl
  \tl_gset_eq:NN\g_mix_playtpe_tl\g_mix_pkgplaytpe_tl
  \tl_gset_eq:NN\g_mix_tools_tl\g_mix_pkgtools_tl
  \tl_gset_eq:NN\g_mix_nrdflt_tl\g_mix_pkgnrdflt_tl
  \tl_gset_eq:NN\g_mix_nav_tl\g_mix_pkgnav_tl

  \tl_gset_eq:NN\g_mix_opt_bg_tl\g_mix_pkgopt_bg_tl
  \tl_gset_eq:NN\g_mix_opt_ls_tl\g_mix_pkgopt_ls_tl
  \tl_gset_eq:NN\g_mix_opt_rm_tl\g_mix_pkgopt_rm_tl
  \tl_gset:Nn\g_mix_opt_psob_tl{Min}
  \tl_gset:Nn\g_mix_opt_coo_tl{0~0~0}
  \tl_gset:Nn\g_mix_opt_ctoc_tl{0~-1~0}
  \tl_gclear:N\g_mix_opt_ciiw_tl
  \fp_gset:Nn\g_mix_opt_roo_fp{1e-9}
  \fp_gset:Nn\g_mix_opt_aac_fp{30}
  \fp_gset:Nn\g_mix_opt_oscale_fp{1}
  \fp_gset:Nn\g_mix_opt_roll_fp{0}

  \bool_set_false:N\l_mix_roo_bool
  \bool_gset_false:N\g_mix_opt_ciiw_bool
  \bool_gset_false:N\g_mix_opt_iiidortho_bool

  \tl_clear:N\l_mix_iiidviewarray_tl
  \tl_gclear:N\g_mix_vfile_tl
}

%3D settings to be reset before creating an additional view
\cs_new:Nn\mix_iiidreset:{
  \tl_clear:N\l_mix_bg_tl
  \tl_clear:N\l_mix_ls_tl
  \tl_clear:N\l_mix_rm_tl
  \tl_set:Nn\l_mix_psob_tl{Min}
  \tl_set:Nn\l_mix_coo_tl{0~0~0}
  \tl_set:Nn\l_mix_ctoc_tl{0~-1~0}
  \tl_clear:N\l_mix_ciiw_tl

  \fp_set:Nn\l_mix_roo_fp{1e-9}
  \fp_set:Nn\l_mix_aac_fp{30}
  \fp_set:Nn\l_mix_oscale_fp{1}
  \fp_set:Nn\l_mix_roll_fp{0}

  \bool_set_false:N\l_mix_roo_bool
  \bool_set_false:N\l_mix_ciiw_bool
  \bool_set_false:N\l_mix_iiidortho_bool

  \tl_clear:N\l_mix_naarray_tl %array of node dicts
  \tl_clear:N\l_mix_saarray_tl %array of crosssect dicts
  \tl_set_eq:NN\l_mix_nr_tl\g_mix_nrdflt_tl %keep or restore part attributes
}

%wrong image resource for 3D
\msg_set:nnn{media9}{wrong~image~resource}{
  Image~resource~file\\~~'#1'\\has~wrong~type.\\\\
  In~3D~context,~driver~#2~only~accepts~files~of~type\\#3\\
  as~image~resources.
}

\cs_new:Nn\mix_insert_btnocg:{%OCG for play button overlay
  \ocgbase_new_ocg:nnn{MediaPlayButton\int_use:N\g_mix_rmcnt_int}{
    /Print<</PrintState/OFF>>/Export<</ExportState/OFF>>
  }{off}
  \tl_gset:Nx\g_mix_btnocg_tl{\ocgbase_last_ocg:}
}

%output mode dependent command definitions
\sys_if_output_pdf:TF{
  \cs_new:Nn\mix_ndname:n{%#1:HEX encoded string
    %converted to binary UTF16BE using \pdfunescapehex (pdfTeX only)
    \tl_set:Nn\l_mix_ndname_tl{\mix_unescapehex:n{#1}}
  }
}{
  \bool_if:NTF\g_mix_dvipdfmx_bool{ %dvipdfmx/XeTeX
    \cs_new:Nn\mix_ndname:n{%#1:HEX encoded UTF16BE string
      \tl_set:Nn\l_mix_ndname_tl{<#1>}
    }
  }{
    %3DNode name
    \cs_new:Nn\mix_ndname:n{%#1:HEX encoded unicode string
      \special{ps:~
        /mix@unicode~65535~string~def~
        (#1)~/ASCIIHexDecode~filter~mix@unicode~readstring~pop~
        /mix@unicode~exch~def~
      }
      %converted to binary UTF16BE by ps2pdf
      \tl_set:Nn\l_mix_ndname_tl{mix@unicode}
    }
  }
}

\cs_new:Nn\mix_embedasset:n{ %#1 file name or url
  %check if #1 is online resource
  \bool_set_false:N\l_mix_url_bool\tl_set:Nx\l_tmpa_tl{#1}
  \regex_match:nVT{(^[Hh][Tt][Tt][Pp][Ss]?|^[Ff][Tt][Pp]):\/\/}\l_tmpa_tl{
    \bool_set_true:N\l_mix_url_bool
  }
  \filename@parse{#1}
  \tl_set:Nx\l_mix_base_tl{\filename@base}
  \tl_set:Nx\l_mix_ext_tl{\tl_lower_case:n{\filename@ext}}
  \bool_if:NTF\l_mix_url_bool{
    \cs_if_exist:cF{url_#1}{
      \mix_pdfobj:nnn{}{dict}{/FS/URL/F(#1)}
      \tl_gset:cx{url_#1}{\mix_pdflastobj:}
    }
    %every new url should be added to assets tree of the current annot
    \cs_if_exist:cF{url_\int_use:c{g_mix_rmcnt_int}_#1}{
      \tl_gput_right:Nx\g_mix_assets_tl{~(#1)~\tl_use:c{url_#1}}
      \tl_new:c{url_\int_use:c{g_mix_rmcnt_int}_#1}
    }
    \tl_gset:Nx\g_mix_lastasset_tl{\tl_use:c{url_#1}}
  }{
    \file_if_exist:nTF{#1}{
      \file_get_full_name:nN{#1}\l_mix_file_tl
    }{
      \msg_error:nnx{media9}{file~not~found}{#1}
    }
    \bool_if:nTF{
      %in 3D context, image resources must be embedded as Image XObjects, not
      %as file streams
      \g_mix_iiid_bool && (
        \str_if_eq_p:Vn\l_mix_ext_tl{jpg}
        || \str_if_eq_p:Vn\l_mix_ext_tl{jpeg}
        || \str_if_eq_p:Vn\l_mix_ext_tl{png}
        || \str_if_eq_p:Vn\l_mix_ext_tl{jbig2}
        || \str_if_eq_p:Vn\l_mix_ext_tl{jb2}
        || \str_if_eq_p:Vn\l_mix_ext_tl{ps}
        || \str_if_eq_p:Vn\l_mix_ext_tl{eps}
        || \str_if_eq_p:Vn\l_mix_ext_tl{pdf}
      )
    }{
      \cs_if_exist:cF{imgXobj_\mix_filemdfivesum:n{\l_mix_file_tl}}{
        \mix_pdfximage:n{\l_mix_file_tl}
        \tl_gset:cx{imgXobj_\mix_filemdfivesum:n{\l_mix_file_tl}}{
          \mix_pdflastximage:
        }
      }
      %create fake FileSpec for current file name if not yet existent
      \cs_if_exist:cF{ImgFileSpecFor3D_#1}{
        \tl_gset:cx{ImgFileSpecFor3D_#1}{
          \tl_use:c{imgXobj_\mix_filemdfivesum:n{\l_mix_file_tl}}
        }
      }
      %add FileSpec to assets tree of current annot
      \cs_if_exist:cF{fileAsset_\int_use:c{g_mix_rmcnt_int}_#1}{
        \tl_gput_right:Nx\g_mix_assets_tl{~(#1)~\tl_use:c{ImgFileSpecFor3D_#1}}
        \tl_new:c{fileAsset_\int_use:c{g_mix_rmcnt_int}_#1}
      }
      \tl_gset:Nx\g_mix_lastasset_tl{\tl_use:c{ImgFileSpecFor3D_#1}}
    }{
      %remaining file types in 3D context and any file type in case of Flash
      %context will be embedded as ordinary fstreams;
      \cs_if_exist:cF{fileEmb_\mix_filemdfivesum:n{\l_mix_file_tl}}{
        \mix_pdfobj:nnn{}{fstream}{{}{\l_mix_file_tl}}
        \tl_gset:cx{fileEmb_\mix_filemdfivesum:n{\l_mix_file_tl}}{
          \mix_pdflastobj:
        }
      }
      %create FileSpec for current file name if not yet existent
      \cs_if_exist:cF{fileSpec_#1}{
        \mix_pdfobj:nnn{}{dict}{
          /Type/Filespec/F~(#1)%/UF~(#1)
          /EF~<</F~\tl_use:c{fileEmb_\mix_filemdfivesum:n{\l_mix_file_tl}}>>
        }
        \tl_gset:cx{fileSpec_#1}{\mix_pdflastobj:}
        \bool_if:NT\g_mix_usrattach_bool{
          \mix_pdfannot:nnnn{0pt}{0pt}{0pt}{
            /Contents~(media~resource)
            /F~2\cs_if_exist_use:N
            /Subtype/FileAttachment
            /FS~\mix_pdflastobj:
          }
        }
      }
      %add FileSpec to assets tree of current annot
      \cs_if_exist:cF{fileAsset_\int_use:c{g_mix_rmcnt_int}_#1}{
        \tl_gput_right:Nx\g_mix_assets_tl{~(#1)~\tl_use:c{fileSpec_#1}}
        \tl_new:c{fileAsset_\int_use:c{g_mix_rmcnt_int}_#1}
      }
      \tl_gset:Nx\g_mix_lastasset_tl{\tl_use:c{fileSpec_#1}}
    }
  }
}

\cs_new:Nn\mix_draftbox:n{ %#1 text string to be shown in the draft box centre
  \hbox_overlap_right:n{
    \hbox_to_wd:nn{\g_mix_wd_tl}{
      \vrule~height~\g_mix_ht_tl~depth~\g_mix_dp_tl\hss
      \vrule
    }
  }
  \box_move_down:nn{\g_mix_dp_tl}{
    \hbox_to_wd:nn{\g_mix_wd_tl}{
      \vbox_to_ht:nn{\g_mix_tt_tl}{
        \hrule~width~\g_mix_wd_tl\vss
        \hbox_to_wd:nn{\g_mix_wd_tl}{\ttfamily{\tiny#1}\hss}\vss
        \hrule
      }
    }
  }
}

\msg_set:nnn{media9}{zero~size}{
  Media~annotation~\msg_line_context:\ has~zero\\
  size~in~at~least~one~dimension.\\\\
  Provide~a~poster~text~with~non-zero~width~and\\
  height,~or~specify~a~suitable~size~via~`width'\\
  and~`height'~options.
}

\msg_set:nnn{media9}{zero~width}{
  Media~annotation~\msg_line_context:\ has~zero~width.\\\\
  Provide~a~poster~text~with~non-zero~width~or\\
  set~a~valid~one~using~the~`width'~option.
}

\msg_set:nnn{media9}{zero~height}{
  Media~annotation~\msg_line_context:\ has~zero~height.\\\\
  Provide~a~poster~text~with~non-zero~height~or\\
  set~a~valid~height~using~one~of~`height'~or\\
  `totalheight'~options.
}


%calculates widget dimensions from natural ones, taking resizing options
%into account
\int_new:N\g_mix_resizeflag_int% resizing flags according to options given
\cs_new:Nn\mix_scale:n{% #1 box number
  %totalheight overrides height if both height & totalheight options were given
  \bool_if:nT{
    \int_compare_p:n{\g_mix_resizeflag_int=\c_three} ||
    \int_compare_p:n{\g_mix_resizeflag_int=\c_seven}
  }{\int_gsub:Nn\g_mix_resizeflag_int{\c_two}}
  \group_begin:
    %natural dimensions \width, \height, \depth, \totalheight
    \tl_set:Nn\width {\box_wd:N#1}
    \tl_set:Nn\height{\box_ht:N#1}
    \tl_set:Nn\depth {\box_dp:N#1}
    \tl_set:Nn\totalheight{\dimexpr\height+\depth\relax}
    \tl_gset:Nx\g_tmpa_tl{\dim_eval:n{\width}}
    \tl_gset:Nx\g_tmpb_tl{\dim_eval:n{\totalheight}}
    %evaluate width/height/totalheight options
    \tl_gset:Nx\g_mix_wd_tl{\dim_abs:n{\g_mix_wdarg_tl}}
    \tl_gset:Nx\g_mix_ht_tl{\dim_abs:n{\g_mix_htarg_tl}}
    \tl_gset:Nx\g_mix_tt_tl{\dim_abs:n{\g_mix_ttarg_tl}}
    \dim_compare:nT{\width=\c_zero_dim}{\box_gset_wd:Nn#1{\g_mix_wd_tl}}
    \dim_compare:nT{\totalheight=\c_zero_dim}{
      \bool_if:nT{ %height option given
        \int_compare_p:n{\g_mix_resizeflag_int=\c_six}||
        \int_compare_p:n{\g_mix_resizeflag_int=\c_two}
      }{\box_gset_ht:Nn#1{\g_mix_ht_tl}}
      \bool_if:nT{ %totalheight option given
        \int_compare_p:n{\g_mix_resizeflag_int=\c_five}||
        \int_compare_p:n{\g_mix_resizeflag_int=\c_one}
      }{\box_gset_ht:Nn#1{\g_mix_tt_tl}}
    }
  \group_end:
  \tl_gset:Nn\g_mix_dp_tl{\c_zero_dim} %to be initialised here
  %now resize (originally non-zero size) poster box according to the
  %options given
  \bool_if:nF{
    \dim_compare_p:n{\g_tmpa_tl=\c_zero_dim}||
    \dim_compare_p:n{\g_tmpb_tl=\c_zero_dim}
  }{
    %bit 2^2=width, 2^1=height, 2^0=totalhight given
    \int_case:nn{\g_mix_resizeflag_int}{
      {\c_one}{
        \box_resize_to_ht_plus_dp:Nn#1{\g_mix_tt_tl}
      }
      {\c_two}{
        \box_resize_to_ht:Nn#1{\g_mix_ht_tl}
      }
      {\c_four}{
        \box_resize_to_wd:Nn#1{\g_mix_wd_tl}
      }
      {\c_five}{
        \bool_if:NTF\g_mix_usriso_bool{
          \dim_set:Nn\l_tmpa_dim{
            (\box_ht:N#1+\box_dp:N#1)*\dim_ratio:nn{\g_mix_wd_tl}{\box_wd:N#1}
          }
          \dim_set:Nn\l_tmpa_dim{\dim_abs:n{\l_tmpa_dim}}
          \dim_set:Nn\l_tmpb_dim{\dim_abs:n{\g_mix_tt_tl}}
          \dim_compare:nTF{\l_tmpa_dim<\l_tmpb_dim}{
            \box_resize_to_wd:Nn#1{\g_mix_wd_tl}
          }{
            \box_resize_to_ht_plus_dp:Nn#1{\g_mix_tt_tl}
          }
        }{
          \box_resize_to_wd_and_ht_plus_dp:Nnn#1{\g_mix_wd_tl}{\g_mix_tt_tl}
        }
      }
      {\c_six}{
        \bool_if:NTF\g_mix_usriso_bool{
          \dim_set:Nn\l_tmpa_dim{
            \box_ht:N#1*\dim_ratio:nn{\g_mix_wd_tl}{\box_wd:N#1}
          }
          \dim_set:Nn\l_tmpa_dim{\dim_abs:n{\l_tmpa_dim}}
          \dim_set:Nn\l_tmpb_dim{\dim_abs:n{\g_mix_ht_tl}}
          \dim_compare:nTF{\l_tmpa_dim<\l_tmpb_dim}{
            \box_resize_to_wd:Nn#1{\g_mix_wd_tl}
          }{
            \box_resize_to_ht:Nn#1{\g_mix_ht_tl}
          }
        }{
          \box_resize_to_wd_and_ht:Nnn#1{\g_mix_wd_tl}{\g_mix_ht_tl}
        }
      }
    }
  }
  %apply scaling factor
  \box_scale:Nnn#1{\g_mix_scalearg_tl}{\g_mix_scalearg_tl}
  %dimensions after resizing
  \tl_gset:Nx\g_mix_wd_tl{\dim_use:N\box_wd:N#1}
  \tl_gset:Nx\g_mix_ht_tl{\dim_use:N\box_ht:N#1}
  \tl_gset:Nx\g_mix_dp_tl{\dim_use:N\box_dp:N#1}
  \tl_gset:Nx\g_mix_tt_tl{\dim_eval:n{\box_ht:N#1+\box_dp:N#1}}
  \dim_compare:nT{\g_mix_wd_tl=\c_zero_dim}{\msg_warning:nn{media9}{zero~width}}
  \dim_compare:nT{\g_mix_tt_tl=\c_zero_dim}{
      \msg_warning:nn{media9}{zero~height}}
}

\bool_new:N\g_mix_iiid_bool
\int_new:N\l_mix_lineno_int

\NewDocumentCommand\addmediapath{m}{
  \str_set:Nn \l_tmpa_str {#1/}
  \seq_put_right:NV \l_file_search_path_seq \l_tmpa_str
}

%play button overlay; two versions: fancy and plain
\box_new:N\l_mix_pbtn_box
\ExplSyntaxOff
\newdimen\mix@btn@dim
\def\g@mix@pbtn@fancy@tl#1#2{% width, total height
  \ifdefined\tikz%
    \mix@btn@dim=\dimexpr\baselineskip*3\relax%
    \ifdim#1<\mix@btn@dim\mix@btn@dim=#1\fi%
    \ifdim#2<\mix@btn@dim\mix@btn@dim=#2\fi%
    \tikz[x=\mix@btn@dim,y=\mix@btn@dim]{%
      \shade [opacity=\ifdim#2>\dimexpr\baselineskip*6\relax0.6\else0\fi,
        shading angle=-180,even odd rule]
        (-\dimexpr#1/2\relax,-0.5) rectangle (\dimexpr#1/2\relax,0.5)
        (0,0) circle (0.4);
      \shade [ball color=gray,opacity=0.6] (0,0) circle (0.4);
      \fill [color=white,opacity=0.6] %triangle
        (-0.152,0.224)--(-0.152,-0.224)--+(30:0.4844)--cycle;
    }%
  \else%
    \ifcsname g_mix_rerunwarned_tl\endcsname\else%
      \expandafter\gdef\csname g_mix_rerunwarned_tl\endcsname{}%
      \AtEndDocument{\csname msg_warning:nn\endcsname{media9}{rerun}}%
    \fi%
  \fi%
  \ifdefined\mix@AtEnd@Doc\else%
    \@bsphack\protected@write\@mainaux{}{%
      \string\ifcsname\space mix@AtEnd@Doc\string\endcsname\string\else%
        \string\AtBeginDocument{\string\RequirePackage{tikz}}%
      \string\fi%
    }\@esphack%
    \gdef\mix@AtEnd@Doc{}%
  \fi%
}
\def\g@mix@pbtn@plain@tl#1#2{% width, total height
  \ifdefined\tikz%
    \mix@btn@dim=\dimexpr\baselineskip*3\relax%
    \ifdim#1<\mix@btn@dim\mix@btn@dim=#1\fi%
    \ifdim#2<\mix@btn@dim\mix@btn@dim=#2\fi%
    \tikz[x=\mix@btn@dim,y=\mix@btn@dim]{%
      \fill [opacity=\ifdim#2>\dimexpr\baselineskip*6\relax0.5\else0\fi,
        color=gray,even odd rule]
        (-\dimexpr#1/2\relax,-0.5) rectangle (\dimexpr#1/2\relax,0.5);
        (0,0) circle (0.4);
      \fill [color=black,opacity=0.5] (0,0) circle (0.4);
      \fill [color=white,opacity=0.8]
        (-0.152,0.224)--(-0.152,-0.224)--+(30:0.4844)--cycle;
    }%
  \else%
    \ifcsname g_mix_rerunwarned_tl\endcsname\else%
      \expandafter\gdef\csname g_mix_rerunwarned_tl\endcsname{}%
      \AtEndDocument{\csname msg_warning:nn\endcsname{media9}{rerun}}%
    \fi%
  \fi%
  \ifdefined\mix@AtEnd@Doc\else%
    \@bsphack\protected@write\@mainaux{}{%
      \string\ifcsname\space mix@AtEnd@Doc\string\endcsname\string\else%
        \string\AtBeginDocument{\string\RequirePackage{tikz}}%
      \string\fi%
    }\@esphack%
    \gdef\mix@AtEnd@Doc{}%
  \fi%
}
\ExplSyntaxOn

%environment for setting LTR typesetting direction with e-TeX based engines
\cs_new:Nn\mix_beginLTR:{
  \cs_if_exist:NT\TeXXeTstate{
    \int_compare:nT{\TeXXeTstate>\c_zero}{\beginL}
  }
}
\cs_new:Nn\mix_endLTR:{
  \cs_if_exist:NT\TeXXeTstate{
    \int_compare:nT{\TeXXeTstate>\c_zero}{\endL}
  }
}

\ior_new:N\l_mix_vfile_stream %file stream for 3D views files
\NewDocumentCommand\includemedia{O{}mm}{%#1 options, #2 text/image #3 media file
  \mix_uriend:
  \group_begin:
  \mix_beginLTR:
  \leavevmode
  %empty stream as appearance dummy
  \cs_if_exist:NF\g_mix_appearance_tl{
    \hbox_set:Nn\l_mix_poster_box{\phantom{\rule{1pt}{1pt}}}
    \mix_pdfxform:n{\l_mix_poster_box}
    \tl_gset:Nx\g_mix_appearance_tl{\mix_pdflastxform:}
  }
  \mix_reset:
  \mix_uribegin: %treat URI characters correctly
  \keys_set:nn{media9/user}{#1}
  \mix_uriend:
  \tl_greplace_all:Nnn\g_mix_flashvars_tl{~&}{&}
  \tl_greplace_all:Nnn\g_mix_flashvars_tl{&~}{&}
  \tl_greplace_all:Nnn\g_mix_flashvars_tl{~=}{=}
  \tl_greplace_all:Nnn\g_mix_flashvars_tl{=~}{=}
  \tl_gtrim_spaces:N\g_mix_flashvars_tl

  \cs_if_exist:NT\Ginput@path{\cs_set_eq:NN\input@path\Ginput@path}

  %\hbox_set:Nn\l_mix_poster_box{\group_begin:#2\group_end:}
  %\hbox_set:Nn\l_mix_poster_box{#2}
  \sbox\l_mix_poster_box{#2}
  \mix_scale:n{\l_mix_poster_box}
  \bool_if:nT{
    \dim_compare_p:n{\g_mix_tt_tl=\c_zero_dim}||
    \dim_compare_p:n{\g_mix_wd_tl=\c_zero_dim}
  }{
    \tl_gset:Nn\g_mix_usrpbtn_tl{none}
  }
  \bool_if:NTF\g_mix_usrdraft_bool{
    \tl_if_empty:NF\g_mix_usrlabel_tl{
      \mix_keytoaux_now:nn{ann@\g_mix_usrlabel_tl}{draft}
    }
    \tl_if_blank:oTF{#2}{
      \mix_uribegin: %treat URI characters correctly
      \mix_draftbox:n{\tl_to_str:n{#3}}
      \mix_uriend:
    }{
      \hbox_to_wd:nn{\g_mix_wd_tl}{
        \vrule~width~\c_zero_dim~height~\g_mix_ht_tl~depth~\g_mix_dp_tl
        \box_use:N\l_mix_poster_box\hss
      }
    }
  }{
    \bool_if:nF{\str_if_eq_p:Vn\g_mix_usrpbtn_tl{none}}{
      %attach script that switches off play button overlay upon activation
      \mix_pdfobj:nnn{}{stream}{
        {}{
          var~ocgs=host.getOCGs(host.pageNum);
          for(var~i=0;i<ocgs.length;i++){
            if(ocgs[i].name=='MediaPlayButton\int_use:N\g_mix_rmcnt_int'){
              ocgs[i].state=false;
            }
          }
        }
      }
      \mix_pdfobj:nnn{}{dict}{
        /Type/Filespec/EF~<</F~\mix_pdflastobj:>>/F~(btnoff)%/UF~(btnoff)
      }
      \tl_gset:Nx\g_mix_assets_tl{(btnoff)~\mix_pdflastobj:}
      \tl_set:Nx\l_mix_scripts_tl{~\mix_pdflastobj:~}
      %enforce plain playbutton overlay for XeTeX
      \sys_if_engine_xetex:T{\tl_gset:Nn\g_mix_usrpbtn_tl{plain}}
    }
    %embed main asset
    \mix_uribegin:
    \mix_embedasset:n{#3}
    \bool_if:nTF{
      \str_if_eq_p:Vn\l_mix_ext_tl{prc}||\str_if_eq_p:Vn\l_mix_ext_tl{u3d}
    }{
      \bool_gset_true:N\g_mix_iiid_bool
      \tl_gset:Nn\g_mix_mainassetsub_tl{3D}
    }{
      \str_case_x:nnF{\l_mix_base_tl}{
        {APlayer}{\tl_gset:Nn\g_mix_mainassetsub_tl{Sound}}
        {AudioPlayer}{\tl_gset:Nn\g_mix_mainassetsub_tl{Sound}}
        {VPlayer}{\tl_gset:Nn\g_mix_mainassetsub_tl{Video}}
        {VideoPlayer}{\tl_gset:Nn\g_mix_mainassetsub_tl{Video}}
        {StrobeMediaPlayback}{\tl_gset:Nn\g_mix_mainassetsub_tl{Video}}
      }{\tl_gset:Nn\g_mix_mainassetsub_tl{Flash}}
    }
    \tl_gset:Nx\g_mix_mainasset_tl{~\g_mix_lastasset_tl}
    \mix_uriend:
    %secondary assets (added by addresource)
    \seq_map_function:NN\g_mix_res_seq\mix_embedasset:n
    \seq_map_inline:Nn\g_mix_script_seq{
      \mix_embedasset:n{##1}
      \tl_put_right:Nx\l_mix_scripts_tl{~\g_mix_lastasset_tl}
    }
    %attach 3D calculation script
    \bool_if:nT{\g_mix_iiid_bool && \g_mix_iiidcalc_bool}{
      \mix_embedasset:n{3Dmenu.js}
      \tl_put_left:Nx\l_mix_scripts_tl{\g_mix_lastasset_tl~}
    }
    %create 3D views from file (option 3Dviews)
    \bool_if:nT{\g_mix_iiid_bool && !(\tl_if_blank_p:V\g_mix_vfile_tl)}{
      \tl_set:Nn\l_mix_level_tl{-1}
      \int_zero:N\l_mix_viewcnt_int
      \int_zero:N\l_mix_lineno_int

      \ior_open:Nn\l_mix_vfile_stream{\g_mix_vfile_tl}
      \ior_map_inline:Nn\l_mix_vfile_stream{
        \int_incr:N\l_mix_lineno_int
        \keys_set:nn{media9/views}{##1} %process input line
      }
      \ior_close:N\l_mix_vfile_stream
    }
    \bool_if:nT{ %create default 3D view if required
      \g_mix_iiid_bool &&
      (\g_mix_opt_iiidview_bool || \tl_if_blank_p:V\l_mix_iiidviewarray_tl)
    }{
      \tl_set_eq:NN\l_mix_bg_tl\g_mix_opt_bg_tl
      \tl_set_eq:NN\l_mix_ls_tl\g_mix_opt_ls_tl
      \tl_set_eq:NN\l_mix_rm_tl\g_mix_opt_rm_tl
      \tl_set_eq:NN\l_mix_psob_tl\g_mix_opt_psob_tl
      \tl_set_eq:NN\l_mix_coo_tl\g_mix_opt_coo_tl
      \tl_set_eq:NN\l_mix_ctoc_tl\g_mix_opt_ctoc_tl
      \tl_set_eq:NN\l_mix_ciiw_tl\g_mix_opt_ciiw_tl

      \fp_set_eq:NN\l_mix_roo_fp\g_mix_opt_roo_fp
      \fp_set_eq:NN\l_mix_aac_fp\g_mix_opt_aac_fp
      \fp_set_eq:NN\l_mix_oscale_fp\g_mix_opt_oscale_fp
      \fp_set_eq:NN\l_mix_roll_fp\g_mix_opt_roll_fp

      \bool_set_eq:NN\l_mix_ciiw_bool\g_mix_opt_ciiw_bool
      \bool_set_eq:NN\l_mix_iiidortho_bool\g_mix_opt_iiidortho_bool
      \tl_clear:N\l_mix_naarray_tl

      \bool_if:NF\l_mix_ciiw_bool{
        \tl_set:Nx\l_mix_args_tl{\l_mix_coo_tl\space\l_mix_ctoc_tl\space}
        \exp_after:wN\mix_calc_ciiw:w\l_mix_args_tl\q_stop
      }

      \tl_clear:N\l_mix_naarray_tl
      \tl_clear:N\l_mix_saarray_tl
      \tl_set_eq:NN\l_mix_nr_tl\g_mix_nrdflt_tl

      \mix_view:n{Default}
      \tl_set:Nx\l_mix_dfltview_tl{\mix_pdflastobj:}

    }
    \mix_pdfobj:nnn{}{dict}{
      /Type/RichMediaInstance
      /Subtype/\g_mix_mainassetsub_tl
      /Asset~\g_mix_mainasset_tl
      \bool_if:NF\g_mix_iiid_bool{
        /Params~<<
          /Binding\str_if_eq:VnTF\g_mix_transp_tl{true}{
            /Foreground
          }{
            /Background
          }
          \tl_if_blank:VF\g_mix_flashvars_tl{
            /FlashVars~(\g_mix_flashvars_tl)
          }
        >>
      }
    }
    \tl_if_empty:NF\g_mix_usrlabel_tl{
      \mix_keytoaux_now:nn{main@\g_mix_usrlabel_tl}{\mix_pdflastobj:}
    }
    \mix_pdfobj:nnn{}{dict}{
      /Type/RichMediaConfiguration
      /Subtype/\g_mix_mainassetsub_tl
      /Instances~[\mix_pdflastobj:]
    }
    \mix_pdfobj:nnn{}{dict}{
      /Type/RichMediaContent
      /Assets~<</Names~[\g_mix_assets_tl]>>
      /Configurations~[\mix_pdflastobj:]
      \bool_if:nT{
        \g_mix_iiid_bool && !(\tl_if_empty_p:V\l_mix_iiidviewarray_tl)
      }{
        /Views~[\l_mix_iiidviewarray_tl]
      }
    }
    \tl_set:Nx\l_mix_content_tl{\mix_pdflastobj:}
    \bool_if:nT{
      \g_mix_iiid_bool && \str_if_eq_p:Vn\g_mix_playtpe_tl{Oscillating}
    }{
      \tl_gset:Nx\g_mix_playcnt_tl{\int_eval:n{\g_mix_playcnt_tl*2}}
    }
    %determine floating window size
    \bool_if:NT\g_mix_opt_windowed_bool{
      \exp_after:wN\mix_parse_winsizearg:w\g_mix_winsize_tl\q_stop
    }
    \mix_pdfobj:nnn{}{dict}{
      /Activation~<<
        /Condition\g_mix_act_tl
        \bool_if:nT{
          \g_mix_iiid_bool &&
          !(\str_if_eq_p:Vn\g_mix_playtpe_tl{None})
        }{%seems to work only with 3D content
          /Animation~<<
            /Subtype/\g_mix_playtpe_tl
            /PlayCount~\g_mix_playcnt_tl
            /Speed~\g_mix_playspd_tl
          >>
        }
        \bool_if:nT{
          \g_mix_iiid_bool && (
            \g_mix_opt_iiidview_bool || \tl_if_blank_p:V\l_mix_iiidviewarray_tl
          )
        }{/View~\l_mix_dfltview_tl}
        /Presentation~<<
          /Transparent~\g_mix_transp_tl
          \bool_if:NTF\g_mix_opt_windowed_bool{
            /Style/Windowed
            /Window~<<
              /Width~<</Default~\tl_mix_fltwd>>
              /Height~<</Default~\tl_mix_fltht>>
              /Position~<<
                /HOffset~0/VOffset~0
                \str_case_x:nnF{\g_mix_winpos_tl}{
                  {tl}{/VAlign/Near/HAlign/Near}
                  {cl}{/VAlign/Center/HAlign/Near}
                  {bl}{/VAlign/Far/HAlign/Near}
                  {bc}{/VAlign/Far/HAlign/Center}
                  {br}{/VAlign/Far/HAlign/Far}
                  {cr}{/VAlign/Center/HAlign/Far}
                  {tr}{/VAlign/Near/HAlign/Far}
                  {tc}{/VAlign/Near/HAlign/Center}
                }{/HAlign/Center/VAlign/Center}
              >>
            >>
          }{
            /Style/Embedded
          }
          \bool_if:NTF\g_mix_iiid_bool{
            /Toolbar~\g_mix_tools_tl
            /NavigationPane~\g_mix_nav_tl
          }{
            /PassContextClick~\g_mix_contextclick_tl
          }
        >>
        \tl_if_blank:VF\l_mix_scripts_tl{/Scripts~[\l_mix_scripts_tl]}
      >>
      /Deactivation~<</Condition\g_mix_deact_tl>>
    }
    \tl_set:Nx\l_mix_settings_tl{\mix_pdflastobj:}
    \tl_if_empty:NF\g_mix_usrlabel_tl{
      \tl_gset_eq:NN\g_mix_label_tl\g_mix_usrlabel_tl
    }
    % #1:width, #2:height, #3:depth, #4:content (key-value)
    \mix_pdfannot:nnnn{\g_mix_wd_tl}{\g_mix_ht_tl}{\g_mix_dp_tl}{
      /Subtype/RichMedia
      /F~4
      /BS~<</W~0/S/S>>
      /Contents~(media~embedded~by~media9~[\g_mix_version_tl~(\g_mix_date_tl)])
      /NM~(\g_mix_label_tl)
      /AP~<</N~\g_mix_appearance_tl>>
      /RichMediaSettings~\l_mix_settings_tl
      /RichMediaContent~\l_mix_content_tl
    }
    \tl_if_empty:NF\g_mix_usrlabel_tl{
      \mix_keytoaux_now:nn{ann@\g_mix_usrlabel_tl}{\mix_pdflastann:}
      \mix_keytoaux_shipout:nn{page@\g_mix_usrlabel_tl}{
        \noexpand\the\g@mix@page@int}
    }
    \mix_pdfobj:nnn{}{dict}{
      /S/JavaScript/JS~(
        try{
          if(typeof(annotRM)=='undefined'){annotRM=new~Array();}
          if(typeof(annotRM['\g_mix_label_tl'])=='undefined'){
            annotRM['\g_mix_label_tl']=
              this.getAnnotRichMedia(this.pageNum,'\g_mix_label_tl');
          }
          \str_if_eq_x:nnF{\g_mix_usrpbtn_tl}{none}{
            if(typeof(ocgBtn\int_use:N\g_mix_rmcnt_int)=='undefined'){
              var~ocgs=this.getOCGs(this.pageNum);
              for(var~i=0;i<ocgs.length;i++){
                if(ocgs[i].name=='MediaPlayButton\int_use:N\g_mix_rmcnt_int'){
                   var~ocgBtn\int_use:N\g_mix_rmcnt_int=ocgs[i];
                }
              }
            }
            if(
              !annotRM['\g_mix_label_tl'].activated&&(
                app.viewerType=='Reader'||
                app.viewerType=='Exchange'||
                app.viewerType=='Exchange-Pro'
              )&&app.viewerVersion>=9
            ){
              ocgBtn\int_use:N\g_mix_rmcnt_int.state=true;
            }
          }
        }catch(e){}
        this.dirty=false;
      )
    }
    \mix_pdfannot:nnnn{0pt}{0pt}{0pt}{
      /Subtype/Widget
      /FT/Btn/Ff~65537/F~2
      /BS~<</W~0>>
      /T~(fd@\g_mix_label_tl)
      /AA~<</PO~\mix_pdflastobj:~/PV~\mix_pdflastobj:>>
    }
    \mix_appendtofields:n{\mix_pdflastann:}
    \hbox_overlap_right:n{\box_use:N\l_mix_poster_box}
    \str_if_eq_x:nnTF{\g_mix_usrpbtn_tl}{none}{
      \hbox_to_wd:nn{\g_mix_wd_tl}{
        \vrule~width~\c_zero_dim~height~\g_mix_ht_tl~depth~\g_mix_dp_tl\hss
      }
    }{%insert play button overlay
      \mix_insert_btnocg: %create OCG
      \cs_gset_eq:Nc\mix_pbtn:NN{g@mix@pbtn@\g_mix_usrpbtn_tl @tl}
      \group_begin:
      \cs_if_exist:NT\textdir{\textdir TLT}
        \sbox\l_mix_pbtn_box{\mix_pbtn:NN\g_mix_wd_tl\g_mix_tt_tl}
        \box_move_down:nn{\g_mix_dp_tl}{
          \hbox_to_wd:nn{\g_mix_wd_tl}{
            \vbox_to_ht:nn{\g_mix_tt_tl}{
              \vss
              \ocgbase_oc_bdc:n{\g_mix_btnocg_tl}
              \box_use:N\l_mix_pbtn_box
              \ocgbase_oc_emc:
            }
          }
        }
      \group_end:
    }
    \int_gincr:N\g_mix_rmcnt_int
  }
  \mix_endLTR:
  \group_end:
}
\tl_set_eq:NN\l_mix_includemedia_tl\includemedia
\tl_set:Nn\includemedia{\mix_uribegin:\l_mix_includemedia_tl}

%environment \mix_uribegin: ... \mix_uriend: to sanitize possibly
%active chars in URLs (RFC 2396), path specifications and JavaScript
\group_begin:
\char_set_catcode_other:n{`\~}
\cs_new_protected_nopar:Npn\mix_uribegin:{
  \group_begin:
  %code contributed by J. Wright
  \tl_map_inline:nn{.:;?!/"'*+,->=<$@([])^_`|~}{
    \cs_set_nopar:Npx\__mix_tmp:w{\token_to_str:N##1}
    \char_set_active_eq:NN##1\__mix_tmp:w
  }
  \tl_map_inline:nn{\#\&\%\\\{\}}{
    \cs_set_nopar:Npx##1{\token_to_str:N##1}
  }
}
\group_end:
\cs_set_eq:NN\mix_uriend:\group_end:

%macro for building the C2W transformation matrix
\cs_new:Npn\mix_calc_ciiw:w#1~#2~#3~#4~#5~#6\q_stop{
  % #1,#2,#3 centre of orbit coordinates (coo)
  % #4,#5,#6 centre of orbit to camera direction vector (c2c)
  %normalized view vector (opposite to c2c)
  \fp_set:Nn\l_mix_mag_fp{(#4*#4 + #5*#5 + #6*#6)**0.5}
  \fp_set:Nn\l_mix_viewx_fp{-#4/\l_mix_mag_fp}
  \fp_set:Nn\l_mix_viewy_fp{-#5/\l_mix_mag_fp}
  \fp_set:Nn\l_mix_viewz_fp{-#6/\l_mix_mag_fp}

  %camera roll
  \fp_set:Nn\l_mix_sinroll_fp{sin(\l_mix_roll_fp deg)}
  \fp_set:Nn\l_mix_cosroll_fp{cos(\l_mix_roll_fp deg)}

  %top and bottom views
  \fp_set:Nn\l_mix_leftx_fp{-1.0}
  \fp_set:Nn\l_mix_lefty_fp{0.0}
  \fp_set:Nn\l_mix_leftz_fp{0.0}
  \fp_compare:nNnTF\l_mix_viewz_fp<\c_zero_fp{% top view
    %up-vector
    \fp_set:Nn\l_mix_upx_fp{0.0}
    \fp_set:Nn\l_mix_upy_fp{1.0}
    \fp_set:Nn\l_mix_upz_fp{0.0}
  }{% bottom view
    %up-vector
    \fp_set:Nn\l_mix_upx_fp{0.0}
    \fp_set:Nn\l_mix_upy_fp{-1.0}
    \fp_set:Nn\l_mix_upz_fp{0.0}
  }
  \fp_set:Nn\l_mix_sumxy_fp{abs(\l_mix_viewx_fp) + abs(\l_mix_viewy_fp)}
  \fp_compare:nNnF\l_mix_sumxy_fp=\c_zero_fp{% other views than top and bottom
    %up-vector = up_world - (up_world dot view) view
    \fp_set:Nn\l_mix_upx_fp{-\l_mix_viewz_fp*\l_mix_viewx_fp}
    \fp_set:Nn\l_mix_upy_fp{-\l_mix_viewz_fp*\l_mix_viewy_fp}
    \fp_set:Nn\l_mix_upz_fp{-\l_mix_viewz_fp*\l_mix_viewz_fp + 1.0}
    %normalize up-vector
    \fp_set:Nn\l_mix_mag_fp{(\l_mix_upx_fp*\l_mix_upx_fp
      + \l_mix_upy_fp*\l_mix_upy_fp + \l_mix_upz_fp*\l_mix_upz_fp)**0.5}
    \fp_set:Nn\l_mix_upx_fp{\l_mix_upx_fp/\l_mix_mag_fp}
    \fp_set:Nn\l_mix_upy_fp{\l_mix_upy_fp/\l_mix_mag_fp}
    \fp_set:Nn\l_mix_upz_fp{\l_mix_upz_fp/\l_mix_mag_fp}
    %left vector = up x view
    \fp_set:Nn\l_mix_leftx_fp{
      \l_mix_viewz_fp*\l_mix_upy_fp - \l_mix_viewy_fp*\l_mix_upz_fp}
    \fp_set:Nn\l_mix_lefty_fp{
      \l_mix_viewx_fp*\l_mix_upz_fp - \l_mix_viewz_fp*\l_mix_upx_fp}
    \fp_set:Nn\l_mix_leftz_fp{
      \l_mix_viewy_fp*\l_mix_upx_fp - \l_mix_viewx_fp*\l_mix_upy_fp}
    %normalize left vector
    \fp_set:Nn\l_mix_mag_fp{(\l_mix_leftx_fp*\l_mix_leftx_fp
      + \l_mix_lefty_fp*\l_mix_lefty_fp + \l_mix_leftz_fp*\l_mix_leftz_fp)**0.5}
    \fp_set:Nn\l_mix_leftx_fp{\l_mix_leftx_fp/\l_mix_mag_fp}
    \fp_set:Nn\l_mix_lefty_fp{\l_mix_lefty_fp/\l_mix_mag_fp}
    \fp_set:Nn\l_mix_leftz_fp{\l_mix_leftz_fp/\l_mix_mag_fp}
  }

  %apply camera roll
  \fp_set:Nn\l_mix_leftxprime_fp{
    \l_mix_leftx_fp*\l_mix_cosroll_fp + \l_mix_upx_fp*\l_mix_sinroll_fp}
  \fp_set:Nn\l_mix_leftyprime_fp{
    \l_mix_lefty_fp*\l_mix_cosroll_fp + \l_mix_upy_fp*\l_mix_sinroll_fp}
  \fp_set:Nn\l_mix_leftzprime_fp{
    \l_mix_leftz_fp*\l_mix_cosroll_fp + \l_mix_upz_fp*\l_mix_sinroll_fp}

  \fp_set:Nn\l_mix_upxprime_fp{
    \l_mix_upx_fp*\l_mix_cosroll_fp - \l_mix_leftx_fp*\l_mix_sinroll_fp}
  \fp_set:Nn\l_mix_upyprime_fp{
    \l_mix_upy_fp*\l_mix_cosroll_fp - \l_mix_lefty_fp*\l_mix_sinroll_fp}
  \fp_set:Nn\l_mix_upzprime_fp{
    \l_mix_upz_fp*\l_mix_cosroll_fp - \l_mix_leftz_fp*\l_mix_sinroll_fp}

  \fp_set_eq:NN\l_mix_leftx_fp\l_mix_leftxprime_fp
  \fp_set_eq:NN\l_mix_lefty_fp\l_mix_leftyprime_fp
  \fp_set_eq:NN\l_mix_leftz_fp\l_mix_leftzprime_fp
  \fp_set_eq:NN\l_mix_upx_fp\l_mix_upxprime_fp
  \fp_set_eq:NN\l_mix_upy_fp\l_mix_upyprime_fp
  \fp_set_eq:NN\l_mix_upz_fp\l_mix_upzprime_fp

  %translation vector
  \fp_set:Nn\l_mix_transx_fp{#1 - \l_mix_roo_fp*\l_mix_viewx_fp}
  \fp_set:Nn\l_mix_transy_fp{#2 - \l_mix_roo_fp*\l_mix_viewy_fp}
  \fp_set:Nn\l_mix_transz_fp{#3 - \l_mix_roo_fp*\l_mix_viewz_fp}

  %format elements of transformation matrix
  \tl_set:Nx\l_mix_leftx_tl {\fp_to_decimal:n{round((\l_mix_leftx_fp),9)} }
  \tl_set:Nx\l_mix_lefty_tl {\fp_to_decimal:n{round((\l_mix_lefty_fp),9)} }
  \tl_set:Nx\l_mix_leftz_tl {\fp_to_decimal:n{round((\l_mix_leftz_fp),9)} }
  \tl_set:Nx\l_mix_upx_tl   {\fp_to_decimal:n{round((\l_mix_upx_fp),9)}   }
  \tl_set:Nx\l_mix_upy_tl   {\fp_to_decimal:n{round((\l_mix_upy_fp),9)}   }
  \tl_set:Nx\l_mix_upz_tl   {\fp_to_decimal:n{round((\l_mix_upz_fp),9)}   }
  \tl_set:Nx\l_mix_viewx_tl {\fp_to_decimal:n{round((\l_mix_viewx_fp),9)} }
  \tl_set:Nx\l_mix_viewy_tl {\fp_to_decimal:n{round((\l_mix_viewy_fp),9)} }
  \tl_set:Nx\l_mix_viewz_tl {\fp_to_decimal:n{round((\l_mix_viewz_fp),9)} }
  \tl_set:Nx\l_mix_transx_tl{\fp_to_decimal:n{round((\l_mix_transx_fp),9)}}
  \tl_set:Nx\l_mix_transy_tl{\fp_to_decimal:n{round((\l_mix_transy_fp),9)}}
  \tl_set:Nx\l_mix_transz_tl{\fp_to_decimal:n{round((\l_mix_transz_fp),9)}}

  %concat elements to matrix
  \tl_set:Nx\l_mix_ciiw_tl{
    \l_mix_leftx_tl \space
    \l_mix_lefty_tl \space
    \l_mix_leftz_tl \space
    \l_mix_upx_tl   \space
    \l_mix_upy_tl   \space
    \l_mix_upz_tl   \space
    \l_mix_viewx_tl \space
    \l_mix_viewy_tl \space
    \l_mix_viewz_tl \space
    \l_mix_transx_tl\space
    \l_mix_transy_tl\space
    \l_mix_transz_tl
  }
}

% 3D view object
\cs_new:Nn\mix_view:n{
  \tl_set:Nx\l_mix_oscale_tl{\fp_to_decimal:n{round((\l_mix_oscale_fp),9)}}
  \tl_set:Nx\l_mix_aac_tl{\fp_to_decimal:n{round((\l_mix_aac_fp),9)}}
  \tl_set:Nx\l_mix_roo_tl{\fp_to_decimal:n{round((\l_mix_roo_fp),9)}}
  \mix_pdfobj:nnn{}{dict}{
    /MS/M
    /P<<
      \bool_if:NTF\l_mix_iiidortho_bool{
        /Subtype/O/OS~\l_mix_oscale_tl/OB/\l_mix_psob_tl
      }{
        /Subtype/P/FOV~\l_mix_aac_tl/PS/\l_mix_psob_tl
      }
    >>
    /C2W~[\l_mix_ciiw_tl]
    /CO~\l_mix_roo_tl
    \l_mix_nr_tl
    /NA~[\l_mix_naarray_tl]
    /SA~[\l_mix_saarray_tl]
    \l_mix_bg_tl\l_mix_ls_tl\l_mix_rm_tl
    /XN~(#1)/IN~(#1)
  }
}

%document command options

\msg_set:nnnn{media9}{unknown~option}{
  Line~\msg_line_number: :~Unknown~option~`#1'.
}{
  Option~'#1'~is~not~known~by~media9:\\
  perhaps~it~is~spelled~incorrectly.
}

\msg_set:nnn{media9}{deprecated~option}{
  Line~\msg_line_number: :~Option~`#1'~deprecated.\\
  #2
}

\bool_new:N\g_mix_usrdraft_bool
\bool_new:N\g_mix_usriso_bool
\bool_new:N\g_mix_usrattach_bool
\bool_new:N\g_mix_usrpbtn_bool
\bool_new:N\g_mix_opt_iiidview_bool
\bool_new:N\l_mix_roo_bool
\bool_new:N\g_mix_opt_ciiw_bool
\bool_new:N\g_mix_opt_iiidortho_bool
\bool_new:N\l_mix_ciiw_bool
\bool_new:N\l_mix_iiidortho_bool
\bool_new:N\g_mix_opt_windowed_bool

\seq_new:N\g_mix_res_seq
\seq_new:N\g_mix_script_seq
\tl_new:N\g_mix_rmnames_tl

\keys_define:nn{media9/user}{
  %user override automatic label
  label .code:n = {
    \tl_gset:Nx\g_mix_usrlabel_tl{#1}
    \tl_gtrim_spaces:N\g_mix_usrlabel_tl
    \cs_if_exist:cTF{rm@#1}{
      \msg_warning:nnx{media9}{same~label}{#1}
      \cs_if_exist:NF\g_mix_samelabel_tl{
        \tl_new:N\g_mix_samelabel_tl
        \AtEndDocument{\msg_warning:nn{media9}{multiple~labels}}
      }
    }{
      \tl_new:c{rm@#1}
    }
  },
  label .value_required:n = {true},

  width .code:n = {
    \tl_gset:Nn\g_mix_wdarg_tl{#1}
    \tl_if_exist:NF\l_mix_usrwd_tl{
      \int_gadd:Nn\g_mix_resizeflag_int{\c_four}
      \tl_set:Nn\l_mix_usrwd_tl{}
    }
  },
  width .value_required:n = {true},

  height .code:n = {
    \tl_gset:Nn\g_mix_htarg_tl{#1}
    \tl_if_exist:NF\l_mix_usrht_tl{
      \int_gadd:Nn\g_mix_resizeflag_int{\c_two}
      \tl_set:Nn\l_mix_usrht_tl{}
    }
  },
  height .value_required:n = {true},

  totalheight .code:n = {
    \tl_gset:Nn\g_mix_ttarg_tl{#1}
    \tl_if_exist:NF\l_mix_usrtt_tl{
      \int_gadd:Nn\g_mix_resizeflag_int{\c_one}
      \tl_set:Nn\l_mix_usrtt_tl{}
    }
  },
  height .value_required:n = {true},

  depth .code:n = {
    \msg_warning:nnnn{media9}{deprecated~option}{depth}{
      Ignoring~`depth'~option.
    }
  },

  keepaspectratio .choice:,
  keepaspectratio / true .code:n = {\bool_gset_true:N\g_mix_usriso_bool},
  keepaspectratio / false .code:n = {\bool_gset_false:N\g_mix_usriso_bool},
  keepaspectratio .default:n = {true},

  scale .code:n = {\tl_gset:Nx\g_mix_scalearg_tl{#1}},
  scale .value_required:n = {true},

  url .code:n = {
    \msg_warning:nnnn{media9}{deprecated~option}{url}{
      Instead,~use~a~fully~qualified~URL~starting~with~`http://'~or~`ftp://'.
    }
  },

  addresource .code:n = {\seq_gput_right:Nn\g_mix_res_seq{#1}},
  addresource .value_required:n = {true},

  add3Djscript .code:n = {\seq_gput_right:Nn\g_mix_script_seq{#1}},
  add3Djscript .value_required:n = {true},

  flashvars .tl_gset_x:N = \g_mix_flashvars_tl,
  flashvars .value_required:n = {true},

  activate .choice:,
  activate / pagevisible .code:n = {\tl_gset:Nn\g_mix_act_tl{/PV}},
  activate / pageopen .code:n = {\tl_gset:Nn\g_mix_act_tl{/PO}},
  activate / onclick .code:n = {\tl_gset:Nn\g_mix_act_tl{/XA}},
  activate .value_required:n = {true},

  deactivate .choice:,
  deactivate / pageinvisible .code:n = {\tl_gset:Nn\g_mix_deact_tl{/PI}},
  deactivate / pageclose .code:n = {\tl_gset:Nn\g_mix_deact_tl{/PC}},
  deactivate / onclick .code:n = {\tl_gset:Nn\g_mix_deact_tl{/XD}},
  deactivate .value_required:n = {true},

  draft .choice:,
  draft / true .code:n = {\bool_gset_true:N\g_mix_usrdraft_bool},
  draft / false .code:n = {\bool_gset_false:N\g_mix_usrdraft_bool},
  draft .default:n = {true},

  final .choice:,
  final / true .code:n = {\bool_gset_false:N\g_mix_usrdraft_bool},
  final / false .code:n = {\bool_gset_true:N\g_mix_usrdraft_bool},
  final .default:n = {true},

  attachfiles .choice:,
  attachfiles / true .code:n = {\bool_gset_true:N\g_mix_usrattach_bool},
  attachfiles / false .code:n = {\bool_gset_false:N\g_mix_usrattach_bool},
  attachfiles .default:n = {true},

  noplaybutton .choice:,
  noplaybutton / true .code:n = {\tl_gset:Nn\g_mix_usrpbtn_tl{none}},
  noplaybutton .default:n = {true},

  playbutton .choice:,
  playbutton / fancy .code:n = {\tl_gset:Nn\g_mix_usrpbtn_tl{fancy}},
  playbutton / plain .code:n = {\tl_gset:Nn\g_mix_usrpbtn_tl{plain}},
  playbutton / none .code:n = {\tl_gset:Nn\g_mix_usrpbtn_tl{none}},
  playbutton .default:n = {fancy},

  transparent .choices:nn = {true,false}{
    \tl_gset:Nx\g_mix_transp_tl{\l_keys_choice_tl}
  },
  transparent .default:n = {true},

  passcontext .choices:nn = {true,false}{
    \tl_gset:Nx\g_mix_contextclick_tl{\l_keys_choice_tl}
  },
  passcontext .default:n = {true},

  windowed .code:n = {
    \str_if_eq:nnTF{#1}{false}{
      \bool_gset_false:N\g_mix_opt_windowed_bool
    }{
      \bool_gset_true:N\g_mix_opt_windowed_bool
      \tl_set:Nx\l_tmpa_tl{#1}
      \tl_remove_all:Nn\l_tmpa_tl{~}
      \mix_parse_windowedarg:N\l_tmpa_tl
    }
  },

  %3D specific options
  3Dplaytype .choice:,
  3Dplaytype / none .code:n = {\tl_gset:Nn\g_mix_playtpe_tl{None}},
  3Dplaytype / linear .code:n = {\tl_gset:Nn\g_mix_playtpe_tl{Linear}},
  3Dplaytype / oscillating .code:n = {
    \tl_gset:Nn\g_mix_playtpe_tl{Oscillating}},
  3Dplaytype .value_required:n = {true},

  3Dplaycount .code:n = {\tl_gset:Nx\g_mix_playcnt_tl{\fp_eval:n{trunc(#1)}}},
  3Dplaycount .value_required:n = {true},

  3Dplayspeed .tl_gset_x:N = \g_mix_playspd_tl,
  3Dplayspeed .value_required:n = {true},

  3Dtoolbar .choices:nn = {true,false}{
    \tl_gset:Nx\g_mix_tools_tl{\l_keys_choice_tl}},
  3Dtoolbar .default:n = {true},

  3Dnavpane .choices:nn = {true,false}{
    \tl_gset:Nx\g_mix_nav_tl{\l_keys_choice_tl}},
  3Dnavpane .default:n = {true},

  3Dpartsattrs .choices:nn = {keep,restore}{
    \tl_set:Nn\l_mix_keep_tl{keep}
    \tl_if_eq:NNTF\l_keys_choice_tl\l_mix_keep_tl{
      \tl_gset:Nn\g_mix_nrdflt_tl{/NR~false}
    }{
      \tl_gset:Nn\g_mix_nrdflt_tl{/NR~true}
    }
  },
  3Dpartsattrs .value_required:n = {true},

  3Dcoo .code:n = {\tl_gset:Nn\g_mix_opt_coo_tl{#1}
    \bool_gset_true:N\g_mix_opt_iiidview_bool},
  3Dcoo .value_required:n = {true},

  3Dc2c .code:n = {\tl_gset:Nn\g_mix_opt_ctoc_tl{#1}
    \bool_gset_true:N\g_mix_opt_iiidview_bool},
  3Dc2c .value_required:n = {true},

  3Dc2w .code:n = {
    \tl_gset:Nx\g_mix_opt_ciiw_tl{#1}
    \bool_gset_true:N\g_mix_opt_iiidview_bool
    \bool_gset_true:N\g_mix_opt_ciiw_bool
  },
  3Dc2w .value_required:n = {true},

  3Droo .code:n = {
    \fp_gset:Nn\g_mix_opt_roo_fp{abs(#1)}
    \fp_compare:nNnT\g_mix_opt_roo_fp<{1e-9}{
      \fp_gset:Nn\g_mix_opt_roo_fp{1e-9}}
    \bool_gset_true:N\g_mix_opt_iiidview_bool
    \bool_set_true:N\l_mix_roo_bool
  },
  3Droo .value_required:n = {true},

  3Daac .code:n = {\fp_gset:Nn\g_mix_opt_aac_fp{#1}
    \bool_gset_true:N\g_mix_opt_iiidview_bool},
  3Daac .value_required:n = {true},

  3Dortho .code:n = {
    \bool_gset_true:N\g_mix_opt_iiidview_bool
    \bool_gset_true:N\g_mix_opt_iiidortho_bool
    \fp_compare:nF{#1=0.0}{
      \fp_gset:Nn\g_mix_opt_oscale_fp{#1}
      \bool_if:NF\l_mix_roo_bool{
        \fp_set:Nn\l_mix_temp_fp{1/#1/2}
        \fp_gset_eq:NN\g_mix_opt_roo_fp\l_mix_temp_fp
      }
    }
  },
  3Dortho .default:n = {1},

  3Droll .code:n = {\fp_gset:Nn\g_mix_opt_roll_fp{#1}
    \bool_gset_true:N\g_mix_opt_iiidview_bool},
  3Droll .value_required:n = {true},

  3Dmenu .bool_gset:N = \g_mix_iiidcalc_bool,

  3Dbg .code:n = {
    \tl_gset:Nx\g_mix_opt_bg_tl{/BG<</Subtype/SC/CS/DeviceRGB/C[#1]/EA~true>>}
  },
  3Dbg .value_required:n = {true},

  3Dlights .code:n = {
    \tl_gset:Nx\g_mix_opt_ls_tl{/LS<</Subtype/#1>>}
  },
  3Dlights .value_required:n = {true},

  3Drender .code:n = {
    \regex_extract_once:nnNTF{
      ^(Transparent(?:Wireframe)?):(0|0\.[0-9]*|\.[0-9]+|1\.?|1\.0*)$
    }{#1}\l_mix_tmp_seq{
      \seq_pop_right:NN\l_mix_tmp_seq\l_mix_alpha_tl
      \seq_pop_right:NN\l_mix_tmp_seq\l_mix_rmode_tl
      \tl_gset:Nx\g_mix_opt_rm_tl{
        /RM<</Subtype/\l_mix_rmode_tl/O~\l_mix_alpha_tl>>
      }
    }{
      \tl_gset:Nx\g_mix_opt_rm_tl{/RM<</Subtype/#1>>}
    }
  },
  3Drender .value_required:n = {true},

  3Dpsob .code:n = {
    \tl_gset:Nx\g_mix_opt_psob_tl{#1}
  },
  3Dpsob .value_required:n = {true},

  3Dviews .code:n = {
    \file_if_exist:nTF{#1}{
      \file_get_full_name:nN{#1}\l_mix_temp_tl
      \tl_gset_eq:NN\g_mix_vfile_tl\l_mix_temp_tl
    }{
      \msg_error:nnx{media9}{file~not~found}{#1}
    }
  },
  3Dviews .value_required:n = {true},

  unknown .code:n = {
    \msg_error:nnx{media9}{unknown~option}{\l_keys_key_tl}
  }
}

%3D views file parsing

%messages related to 3D views file parsing
\msg_set:nnn{media9}{nested~view}{
  File~#1,~line~#2:\\
  A~VIEW~section~cannot~be~nested~into~another~section.
}

\msg_set:nnn{media9}{key~not~allowed}{
  File~#1,~line~#2:\\
  Key~`#3'~not~allowed~here;~must~go~into~#4~section.
}

\msg_set:nnn{media9}{section~not~allowed}{
  File~#1,~line~#2:\\
  #3~not~allowed~here;~must~be~a~sub-section~of~a~#4~section.
}

\msg_set:nnn{media9}{missing~part~name}{
  File~#1,~line~#2:\\
  You~must~provide~a~valid~PART~name~(PART=<part name>),~as~displayed\\
  in~the~model~tree~of~the~3D~object~(go~to~`View'->`Navigation~Panels'\\
  ->`Model~Tree'~in~Adobe~Reader).
}

\msg_set:nnn{media9}{missing~utf16~name}{
  File~#1,~line~#2:\\
  You~must~provide~a~valid~hex~encoded~part~name~(UTF16NAME=<part~name\\
  as~hex~encoded~UTF-16~string>).~Enable~`3Dmenu'~option~and~choose\\
  `Get~Current~View'~from~3D~context~menu~to~generate~correct~views~file\\
  entries.
}

\msg_set:nnn{media9}{too~many~cross~sections}{
  File~#1,~line~#2:\\
  Adobe~Reader~supports~only~one~cross~section~per~3D~view.\\
  I~am~ignoring~this~CROSSSECT.
}

\msg_set:nnn{media9}{no~end~here}{
  File~#1,~line~#2:\\
  There~is~nothing~to~END~here.
}

\cs_new:Npn\mix_parse_vect:w#1~#2~#3\q_stop{
  \fp_set:Nn\l_mix_x_fp{#1}
  \fp_set:Nn\l_mix_y_fp{#2}
  \fp_set:Nn\l_mix_z_fp{#3}
}

\cs_new:Nn\mix_arcsin:Nnnn{
  %#1 result (rad), #2 argument, #3 current term no., #4 total number of
  %terms
  \int_compare:nTF{#3==\c_zero}{
    \fp_set:Nn\l_mix_tmpa_fp{1.0}
    \fp_set:Nn\l_mix_tmpb_fp{1.0}
    \fp_set:Nn\l_mix_tmpc_fp{1.0}
    \fp_set:Nn\l_mix_tmpd_fp{#2}

    \fp_set:Nn#1{#2}
  }{
    \fp_set:Nn\l_mix_tmpa_fp{\l_mix_tmpa_fp * \int_eval:n{2*#3-1}}
    \fp_set:Nn\l_mix_tmpb_fp{\l_mix_tmpb_fp * \int_eval:n{2*#3}}
    \fp_set:Nn\l_mix_tmpc_fp{\int_eval:n{2*#3+1}}
    \fp_set:Nn\l_mix_tmpd_fp{\l_mix_tmpd_fp * #2 * #2}

    \fp_set:Nn#1{#1 + \l_mix_tmpd_fp*\l_mix_tmpa_fp/\l_mix_tmpb_fp/\l_mix_tmpc_fp}
  }
  \int_compare:nF{#3==#4}{
    \mix_arcsin:Nnnn#1{#2}{\int_eval:n{#3+1}}{#4}
  }
}

\cs_new:Nn\mix_angfromxy:Nnn{ %#1 result (deg), #2 x, #3 y
  \fp_set:Nn\l_mix_asinarg_fp{#3/(#2*#2 + #3*#3)**0.5}
  \fp_set:Nn\l_mix_acosarg_fp{#2/(#2*#2 + #3*#3)**0.5}
  \fp_set:Nn\l_mix_halfsqrttwo_fp{2**0.5/2}
  \mix_arcsin:Nnnn\l_mix_arcsin_fp{\l_mix_asinarg_fp}{0}{10}
  \mix_arcsin:Nnnn\l_mix_arccos_fp{\l_mix_acosarg_fp}{0}{10}
  \fp_set:Nn\l_mix_asinarg_fp{abs(\l_mix_asinarg_fp)}
  %determine quadrant
  \fp_compare:nTF{#2>=\c_zero_fp}{
    \fp_compare:nTF{#3>=\c_zero_fp}{ %I
      \fp_compare:nNnTF\l_mix_asinarg_fp<\l_mix_halfsqrttwo_fp{
        \fp_set_eq:NN#1\l_mix_arcsin_fp
      }{
        \fp_set:Nn#1{\c_pi_fp/2 - \l_mix_arccos_fp}
      }
    }{                               %IV
      \fp_compare:nNnTF\l_mix_asinarg_fp<\l_mix_halfsqrttwo_fp{
        \fp_set_eq:NN#1\l_mix_arcsin_fp
      }{
        \fp_set:Nn#1{\l_mix_arccos_fp-\c_pi_fp/2}
      }
    }
  }{
    \fp_compare:nTF{#3>=\c_zero_fp}{ %II
      \fp_compare:nNnTF\l_mix_asinarg_fp<\l_mix_halfsqrttwo_fp{
        \fp_set:Nn#1{\c_pi_fp-\l_mix_arcsin_fp}
      }{
        \fp_set:Nn#1{\c_pi_fp/2-\l_mix_arccos_fp}
      }
    }{                               %III
      \fp_compare:nNnTF\l_mix_asinarg_fp<\l_mix_halfsqrttwo_fp{
        \fp_set:Nn#1{-\c_pi_fp-\l_mix_arcsin_fp}
      }{
        \fp_set:Nn#1{\l_mix_arccos_fp-\c_pi_fp/2}
      }
    }
  }
  \fp_set:Nn#1{#1/deg}
}

\bool_new:N\l_mix_blankndname_bool

%keys for parsing the 3D views file
\keys_define:nn{media9/views}{
  \par .code:n = {}, %allow for but ignore empty lines

  VIEW .code:n = {
    \int_compare:nF{\l_mix_level_tl<\c_zero}{
      \msg_error:nnxx{media9}{nested~view}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}
    }
    \tl_set:Nn\l_mix_level_tl{\c_zero}
    \tl_set:Nn\l_mix_cscount_tl{\c_zero}
    \tl_set:Nx\l_mix_xname_tl{#1}%optional name of the view
    \tl_trim_spaces:N\l_mix_xname_tl
    %reset 3D settings to defaults
    \mix_iiidreset:
  },
  VIEW .default:n = {},

  COO .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{COO}{a~VIEW}
    }
    \tl_set:Nx\l_mix_coo_tl{#1}
  },
  COO .value_required:n = {true},

  C2C .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{C2C}{a~VIEW}
    }
    \tl_set:Nx\l_mix_ctoc_tl{#1}
  },
  C2C .value_required:n = {true},

  C2W .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{C2W}{a~VIEW}
    }
    \tl_set:Nx\l_mix_ciiw_tl{#1}
    \bool_set_true:N\l_mix_ciiw_bool
  },
  C2W .value_required:n = {true},

  ROO .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{ROO}{a~VIEW}
    }
    \fp_set:Nn\l_mix_roo_fp{abs(#1)}
    \fp_compare:nNnT\l_mix_roo_fp<{1e-9}{
      \fp_set:Nn\l_mix_roo_fp{1e-9}}
    \bool_set_true:N\l_mix_roo_bool
  },
  ROO .value_required:n = {true},

  AAC .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{AAC}{a~VIEW}
    }
    \fp_set:Nn\l_mix_aac_fp{#1}
  },
  AAC .value_required:n = {true},

  ORTHO .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{ORTHO}{a~VIEW}
    }
    \bool_set_true:N\l_mix_iiidortho_bool
    \fp_compare:nF{#1=0.0}{
      \fp_set:Nn\l_mix_oscale_fp{#1}
      \bool_if:NF\l_mix_roo_bool{
        \fp_set:Nn\l_mix_temp_fp{1/#1/2}
        \fp_set_eq:NN\l_mix_roo_fp\l_mix_temp_fp
      }
    }
  },
  ORTHO .default:n = {1},

  PSOB .code:n = {
    \int_compare:nTF{\l_mix_level_tl=\c_zero}{
      \tl_set:Nx\l_mix_psob_tl{#1}
    }{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}
        {PSOB}{a~VIEW}
    }
  },
  PSOB .value_required:n = {true},

  ROLL .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{ROLL}{a~VIEW}
    }
    \fp_set:Nn\l_mix_roll_fp{#1}
  },
  ROLL .value_required:n = {true},

  BGCOLOR .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{BGCOLOR}{a~VIEW}
    }
    \tl_set:Nx\l_mix_bg_tl{/BG<</CS/DeviceRGB/C[#1]/EA~true>>}
  },
  BGCOLOR .value_required:n = {true},

  LIGHTS .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{LIGHTS}{a~VIEW}
    }
    \tl_set:Nx\l_mix_ls_tl{/LS<</Subtype/#1>>}
  },
  LIGHTS .value_required:n = {true},

  RENDERMODE .code:n = {
    \bool_if:nF{
      \int_compare_p:n{\l_mix_level_tl=\c_zero} ||
      \int_compare_p:n{\l_mix_level_tl=\c_one}
    }{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}
        {RENDERMODE}{a~VIEW~or~a~PART}
    }
    \int_compare:nT{\l_mix_level_tl=\c_zero}{
      \tl_set:Nx\l_mix_rm_tl{/RM<</Subtype/#1>>}
    }
    \int_compare:nT{\l_mix_level_tl=\c_one}{
      \tl_set:Nx\l_mix_ndrm_tl{/RM<</Subtype/#1>>} %part (=node) render mode
    }
  },
  RENDERMODE .value_required:n = {true},

  PARTSATTRS .choices:nn = {keep,restore}{
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{PARTSATTRS}{VIEW}
    }
    \tl_set:Nn\l_mix_keep_tl{keep}
    \tl_if_eq:NNTF\l_keys_choice_tl\l_mix_keep_tl{
      \tl_set:Nn\l_mix_nr_tl{/NR~false}
    }{
      \tl_set:Nn\l_mix_nr_tl{/NR~true}
    }
  },
  PARTSATTRS .value_required:n = {true},

  PART .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{section~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{PART}{VIEW}
    }
    \bool_set_true:N\l_mix_blankndname_bool
    \bool_set:Nn\l_mix_blankndname_bool{\tl_if_blank_p:o{#1}}
    \tl_set:Nn\l_mix_level_tl{\c_one}
    \tl_set:Nn\l_mix_ndname_tl{(#1)} %part (=node) name
    \tl_set_eq:NN\l_mix_partlineno_int\l_mix_lineno_int
    %default part settings
    \tl_clear:N\l_mix_ndop_tl %opacity
    \tl_clear:N\l_mix_ndvi_tl %visibility
    \tl_clear:N\l_mix_ndrm_tl %render mode
    \tl_clear:N\l_mix_ndtrans_tl%transformation matrix
  },
  PART .default:n = {},

  UTF16NAME .code:n = { %part (=node) name, UTF16, HEX encoded
    \int_compare:nF{\l_mix_level_tl=\c_one}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{UTF16NAME}{PART}
    }
    \tl_if_blank:oT{#1}{
      \msg_error:nnxx{media9}{missing~utf16~name}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}
    }
    \bool_set_false:N\l_mix_blankndname_bool
    \mix_ndname:n{feff#1}
  },
  UTFNAME .default:n = {},

  OPACITY .code:n = {
    \bool_if:nF{
      \int_compare_p:n{\l_mix_level_tl=\c_one} ||
      \int_compare_p:n{\l_mix_level_tl=\c_two}
    }{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}
        {OPACITY}{PART~or~CROSSSECT}
    }
    \int_compare:nT{\l_mix_level_tl=\c_one}{ %part
      \tl_set:Nx\l_mix_ndop_tl{/O~#1}
    }
    \int_compare:nT{\l_mix_level_tl=\c_two}{ %crosssect
      \tl_set:Nx\l_mix_csop_tl{/PO~#1}
    }
  },
  OPACITY .value_required:n = {true},

  VISIBLE .choices:nn = {true,false}{
    \bool_if:nF{
      \int_compare_p:n{\l_mix_level_tl=\c_one} ||
      \int_compare_p:n{\l_mix_level_tl=\c_two}
    }{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}
        {VISIBLE}{PART~or~CROSSSECT}
    }
    \int_compare:nT{\l_mix_level_tl=\c_one}{ %part
      \tl_set:Nx\l_mix_ndvi_tl{/V~\l_keys_choice_tl}
    }
    \int_compare:nT{\l_mix_level_tl=\c_two}{ %crosssect
      \tl_set:Nx\l_mix_cspv_tl{/PV~\l_keys_choice_tl}
    }
  },
  VISIBLE .default:n = {true},

  INTERSECTIONVISIBLE .choices:nn = {true,false}{
    \int_compare:nF{\l_mix_level_tl=\c_two}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{INTERSECTIONVISIBLE}
                                                                  {CROSSSECT}
    }
    \tl_set:Nx\l_mix_csiv_tl{/IV~\l_keys_choice_tl}
  },
  INTERSECTIONVISIBLE .default:n = {true},

  PLANECOLOR .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_two}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{PLANECOLOR}{CROSSSECT}
    }
    \tl_set:Nx\l_mix_cspc_tl{/PC~[/DeviceRGB~#1]}
  },
  PLANECOLOR .value_required:n = {true},

  INTERSECTIONCOLOR .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_two}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{INTERSECTIONCOLOR}
                                                                {CROSSSECT}
    }
    \tl_set:Nx\l_mix_csic_tl{/IC~[/DeviceRGB~#1]}
  },
  INTERSECTIONCOLOR .value_required:n = {true},

  TRANSFORM .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_one}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{TRANSLATE}{PART}
    }
    \seq_set_split:Nnn\l_mix_args_seq{~}{#1}
    \seq_map_inline:Nn\l_mix_args_seq{
      \fp_set:Nn\l_mix_tmpa_fp{##1}
      \tl_set:Nx\l_mix_tmpa_tl{\fp_to_decimal:n{round((\l_mix_tmpa_fp),9)}}
      \tl_put_right:Nx\l_mix_ndtrans_tl{~\l_mix_tmpa_tl}
    }
  },
  TRANSFORM .value_required:n = {true},

  CROSSSECT .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_zero}{
      \msg_error:nnxxxx{media9}{section~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{CROSSSECT}{VIEW}
    }
    \int_compare:nT{\l_mix_cscount_tl>\c_zero}{
      \msg_warning:nnxx{media9}{too~many~cross~sections}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}
    }
    \tl_set:Nn\l_mix_level_tl{\c_two}
    %default settings
    \tl_set:Nn\l_mix_cscentre_tl{0~0~0} %centre of clipping plane
    \tl_set:Nn\l_mix_csorient_tl{null~0~0} %orientation of plane
    \tl_clear:N\l_mix_csop_tl %opacity
    \tl_clear:N\l_mix_cspv_tl %plane visibility
    \tl_clear:N\l_mix_cspc_tl %plane colour
    \tl_clear:N\l_mix_csic_tl %intersection colour
    \tl_clear:N\l_mix_csiv_tl %intersection visibility
  },
  CROSSSECT .value_forbidden:n = {true},

  CENTER .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_two}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{CENTER}{CROSSSECT}
    }
    \tl_set:Nx\l_mix_args_tl{#1\space}
    \exp_after:wN\mix_parse_vect:w\l_mix_args_tl\q_stop
    \tl_set:Nx\l_mix_x_tl{\fp_to_decimal:n{round((\l_mix_x_fp),9)}}
    \tl_set:Nx\l_mix_y_tl{\fp_to_decimal:n{round((\l_mix_y_fp),9)}}
    \tl_set:Nx\l_mix_z_tl{\fp_to_decimal:n{round((\l_mix_z_fp),9)}}
    \tl_set:Nx\l_mix_cscentre_tl{
      \l_mix_x_tl\space
      \l_mix_y_tl\space
      \l_mix_z_tl
    }
  },
  CENTER .value_required:n = {true},

  NORMAL .code:n = {
    \int_compare:nF{\l_mix_level_tl=\c_two}{
      \msg_error:nnxxxx{media9}{key~not~allowed}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}{NORMAL}{CROSSSECT}
    }
    \tl_set:Nx\l_mix_args_tl{#1\space}
    \exp_after:wN\mix_parse_vect:w\l_mix_args_tl\q_stop
    \fp_set:Nn\l_mix_magxy{ %sqrt(x^2+y^2)
      (\l_mix_x_fp*\l_mix_x_fp + \l_mix_y_fp*\l_mix_y_fp)**0.5}
    %rot angle of normal vec around Y axis
    \mix_angfromxy:Nnn\l_mix_roty_fp\l_mix_magxy\l_mix_z_fp
    \fp_set:Nn\l_mix_roty_fp{-\l_mix_roty_fp}
    %rot angle of normal vec around Z axis
    \mix_angfromxy:Nnn\l_mix_rotz_fp\l_mix_x_fp\l_mix_y_fp
    \tl_set:Nx\l_mix_roty_tl{\fp_to_decimal:n{round((\l_mix_roty_fp),9)}}
    \tl_set:Nx\l_mix_rotz_tl{\fp_to_decimal:n{round((\l_mix_rotz_fp),9)}}
    \tl_set:Nx\l_mix_csorient_tl{null~\l_mix_roty_tl\space\l_mix_rotz_tl}
  },
  NORMAL .value_required:n = {true},

  END .code:n = {
    \int_case:nnF{\l_mix_level_tl}{
      {0}{ %VIEW
        \bool_if:NF\l_mix_ciiw_bool{
          \tl_set:Nx\l_mix_args_tl{\l_mix_coo_tl\space\l_mix_ctoc_tl\space}
          \exp_after:wN\mix_calc_ciiw:w\l_mix_args_tl\q_stop
        }
        \int_incr:N\l_mix_viewcnt_int
        \tl_if_blank:VT\l_mix_xname_tl{
          \tl_set:Nx\l_mix_xname_tl{View~\int_use:N\l_mix_viewcnt_int}
        }
        \mix_view:n{\l_mix_xname_tl}
        \tl_put_right:Nx\l_mix_iiidviewarray_tl{~\mix_pdflastobj:}
        \tl_set:Nn\l_mix_level_tl{-1}
      }

      {1}{ %PART
        \bool_if:NT\l_mix_blankndname_bool{
          \msg_error:nnxx{media9}{missing~part~name}
            {\g_mix_vfile_tl}{\int_use:N\l_mix_partlineno_int}
        }

        \mix_pdfobj:nnn{}{dict}{
          /Type/3DNode/N~\l_mix_ndname_tl
          \l_mix_ndop_tl\l_mix_ndvi_tl\l_mix_ndrm_tl
          \tl_if_blank:VF\l_mix_ndtrans_tl{
            /M~[\l_mix_ndtrans_tl]
          }
        }

        \tl_put_right:Nx\l_mix_naarray_tl{~\mix_pdflastobj:}
        \tl_set:Nn\l_mix_level_tl{\c_zero}
      }
      {2}{ %CROSSSECT
        \int_compare:nT{\l_mix_cscount_tl=\c_zero}{
          \mix_pdfobj:nnn{}{dict}{
            /Type/3DCrossSection
            /C~[\l_mix_cscentre_tl]
            /O~[\l_mix_csorient_tl]
            \l_mix_csop_tl\l_mix_cspv_tl\l_mix_cspc_tl
            \l_mix_csic_tl\l_mix_csiv_tl
          }
          \tl_put_right:Nx\l_mix_saarray_tl{~\mix_pdflastobj:}
          \tl_set:Nn\l_mix_cscount_tl{\c_one}
        }
        \tl_set:Nn\l_mix_level_tl{\c_zero}
      }
    }{
      \msg_error:nnxx{media9}{no~end~here}
        {\g_mix_vfile_tl}{\int_use:N\l_mix_lineno_int}
    }
  },
  END .value_forbidden:n = {true},
}

%options for \mediabutton command

%helpers for option parsing
\cs_new:Npn\mix_separate_cmd_from_actn:w#1[#2]#3\q_stop{#1}
\cs_new:Npn\mix_separate_arg_from_actn:w#1[#2]#3\q_stop{#2}
\prg_generate_conditional_variant:Nnn\regex_match:nn{nV}{TF}
\prg_generate_conditional_variant:Nnn\regex_match:nn{nV}{T}
\prg_generate_conditional_variant:Nnn\tl_if_blank:n{v}{F}
\prg_generate_conditional_variant:Nnn\tl_if_eq:nn{Vn}{TF}

\bool_new:N\g_mix_btndraft_bool
\keys_define:nn{media9/mbtndraft}{
  draft .choice:,
  draft / true .code:n = {\bool_gset_true:N\g_mix_btndraft_bool},
  draft / false .code:n = {\bool_gset_false:N\g_mix_btndraft_bool},
  draft .default:n = {true},

  final .choice:,
  final / true .code:n = {\bool_gset_false:N\g_mix_btndraft_bool},
  final / false .code:n = {\bool_gset_true:N\g_mix_btndraft_bool},
  final .default:n = {true},

  unknown .code:n = {}
}
\keys_define:nn{media9/mbtn}{
  draft .code:n = {},
  final .code:n = {},

  tooltip .tl_gset_x:N = \g_mix_tooltip_tl,
  tooltip .value_required:n = {true},

  overface .code:n = {
    \sbox\l_mix_poster_box{
      \bool_if:NTF\g_pbs_lscape_bool{\rotatebox{90}{#1}}{#1}}
    \mix_pdfxform:n{\l_mix_poster_box}
    \tl_gset:Nx\g_mix_overbtn_tl{\mix_pdflastxform:}
  },
  overface .value_required:n = {true},

  downface .code:n = {
    \sbox\l_mix_poster_box{
      \bool_if:NTF\g_pbs_lscape_bool{\rotatebox{90}{#1}}{#1}}
    \mix_pdfxform:n{\l_mix_poster_box}
    \tl_gset:Nx\g_mix_downbtn_tl{\mix_pdflastxform:}
  },
  downface .value_required:n = {true},

  3Dgotoview .code:n = {
    \tl_set:Nx\l_tmpa_tl{#1}              %extract ref
    \regex_replace_once:nnN{([^:]+):??.*}{\1}\l_tmpa_tl
    \tl_trim_spaces:N\l_tmpa_tl
    \tl_if_exist:cTF{ann@\l_tmpa_tl}{
      \str_if_eq_x:nnF{\tl_use:c{ann@\l_tmpa_tl}}{draft}{
        \tl_set:Nx\l_tmpb_tl{#1}          %extract idx
        \regex_replace_once:nnN{[^:]+:?}{}\l_tmpb_tl
        \tl_trim_spaces:N\l_tmpb_tl
        \tl_if_blank:VF\l_tmpb_tl{
          \regex_match:nVTF{^[DFLNP]$}\l_tmpb_tl{
            \tl_set:Nx\l_mix_vidx_tl{/\l_tmpb_tl}
          }{
            \regex_match:nVTF{^\d+$}\l_tmpb_tl{
              \tl_set:Nx\l_mix_vidx_tl{~\l_tmpb_tl}
            }{
              \regex_replace_once:nnN{^\(\s*}{}\l_tmpb_tl
              \regex_replace_once:nnN{\s*\)$}{}\l_tmpb_tl
              \tl_set:Nx\l_mix_vidx_tl{~(\l_tmpb_tl)}
            }
          }
        }
        \mix_pdfobj:nnn{}{dict}{
          /S/JavaScript/JS~(
            if(typeof(annotRM)=='undefined'){annotRM=new~Array();}
            if(typeof(annotRM['\l_tmpa_tl'])=='undefined'){
              annotRM['\l_tmpa_tl']=
                this.getAnnotRichMedia(\tl_use:c{page@\l_tmpa_tl},'\l_tmpa_tl');
            }
            annotRM['\l_tmpa_tl'].activated=true;
          )
          \tl_if_blank:VF\l_tmpb_tl{
            /Next~<<
              /S/GoTo3DView
              /TA~\tl_use:c{ann@\l_tmpa_tl}
              /V\l_mix_vidx_tl
            >>
          }
        }
        \tl_gput_right:Nx\g_mix_btnactions_tl{~\mix_pdflastobj:}
      }
    }{
      \msg_warning:nnx{media9}{undefined~reference}{\l_tmpa_tl}
      \cs_if_exist:NF\g_mix_refundefwarned_tl{
        \tl_new:N\g_mix_refundefwarned_tl
        \AtEndDocument{\msg_warning:nn{media9}{undefined~references}}
      }
    }
  },
  3Dgotoview .value_required:n = {true},

  mediacommand .code:n = {
    \tl_set:Nx\l_tmpa_tl{#1}
    \regex_replace_once:nnN{([^:]+):??.*}{\1}\l_tmpa_tl %extract ref
    \tl_trim_spaces:N\l_tmpa_tl
    \tl_if_exist:cTF{ann@\l_tmpa_tl}{
      \str_if_eq_x:nnF{\tl_use:c{ann@\l_tmpa_tl}}{draft}{
        \tl_set:Nx\l_tmpb_tl{#1}
        \regex_replace_once:nnN{[^:]+\:?}{}\l_tmpb_tl
        \tl_trim_spaces:N\l_tmpb_tl
        \regex_replace_all:nnN{^\{|\}$}{}\l_tmpb_tl
        \tl_set:Nx\l_mix_cmd_tl{
          \exp_after:wN\mix_separate_cmd_from_actn:w\l_tmpb_tl[]\q_stop}
        \tl_trim_spaces:N\l_mix_cmd_tl
        \tl_set:Nx\l_mix_arg_tl{
          \exp_after:wN\mix_separate_arg_from_actn:w\l_tmpb_tl[]\q_stop}
        \tl_trim_spaces:N\l_mix_arg_tl
        \mix_pdfobj:nnn{}{dict}{
          /S/JavaScript/JS~(
            if(typeof(annotRM)=='undefined'){annotRM=new~Array();}
            if(typeof(annotRM['\l_tmpa_tl'])=='undefined'){
              annotRM['\l_tmpa_tl']=
                this.getAnnotRichMedia(\tl_use:c{page@\l_tmpa_tl},'\l_tmpa_tl');
            }
            annotRM['\l_tmpa_tl'].activated=true;
          )
          \tl_if_blank:VF\l_mix_cmd_tl{
            /Next~<<
              /S/RichMediaExecute
              /TA~\tl_use:c{ann@\l_tmpa_tl}
              /TI~\tl_use:c{main@\l_tmpa_tl}
              /CMD~<<
                /C~(\l_mix_cmd_tl)
                \tl_if_blank:VF\l_mix_arg_tl{
                  /A~[\l_mix_arg_tl]
                }
              >>
            >>
          }
        }
        \tl_gput_right:Nx\g_mix_btnactions_tl{~\mix_pdflastobj:}
      }
    }{
      \msg_warning:nnx{media9}{undefined~reference}{\l_tmpa_tl}
      \cs_if_exist:NF\g_mix_refundefwarned_tl{
        \tl_new:N\g_mix_refundefwarned_tl
        \AtEndDocument{\msg_warning:nn{media9}{undefined~references}}
      }
    }
  },
  mediacommand .value_required:n = {true},

  jsaction .code:n = {
    \tl_set:Nx\l_tmpa_tl{#1}
    \regex_match:nVTF{^[^\{:]+:.*$}\l_tmpa_tl{
      \regex_replace_once:nnN{([^:]+):??.*}{\1}\l_tmpa_tl %extract ref
      \tl_trim_spaces:N\l_tmpa_tl
    }{\tl_clear:N\l_tmpa_tl}
    \tl_set:Nx\l_tmpb_tl{#1}
    \tl_if_blank:VF\l_tmpa_tl{
      \tl_if_exist:cF{ann@\l_tmpa_tl}{
        \msg_warning:nnx{media9}{undefined~reference}{\l_tmpa_tl}
        \cs_if_exist:NF\g_mix_refundefwarned_tl{
          \tl_new:N\g_mix_refundefwarned_tl
          \AtEndDocument{\msg_warning:nn{media9}{undefined~references}}
        }
      }
      \regex_replace_once:nnN{[^:]+\:}{}\l_tmpb_tl
    }
    \tl_set:Nx\l_tmpb_tl{\exp_after:wN\use:n\l_tmpb_tl}
    \tl_trim_spaces:N\l_tmpb_tl
    \tl_if_blank:VF\l_tmpb_tl{
    \mix_pdfobj:nnn{}{dict}{
      /S/JavaScript/JS~(
        try{\l_tmpb_tl}catch(e){console.show();console.println(e)})}}
    \bool_lazy_and:nnT{
      \tl_if_exist_p:c{ann@\l_tmpa_tl}
    }{
      !\str_if_eq_x_p:nn{\tl_use:c{ann@\l_tmpa_tl}}{draft}
    }{
      \mix_pdfobj:nnn{}{dict}{
        /S/JavaScript/JS~(
          if(typeof(annotRM)=='undefined'){annotRM=new~Array();}
          if(typeof(annotRM['\l_tmpa_tl'])=='undefined'){
            annotRM['\l_tmpa_tl']=
              this.getAnnotRichMedia(\tl_use:c{page@\l_tmpa_tl},'\l_tmpa_tl');
          }
          annotRM['\l_tmpa_tl'].activated=true;
        )
        \tl_if_blank:VF\l_tmpb_tl{/Next~\mix_pdflastobj:}
      }
    }
    \bool_if:nT{
      \bool_lazy_and_p:nn{
        \tl_if_exist_p:c{ann@\l_tmpa_tl}
      }{
        !\str_if_eq_x_p:nn{\tl_use:c{ann@\l_tmpa_tl}}{draft}
      }
      || !\tl_if_blank_p:V\l_tmpb_tl
    }{
      \tl_gput_right:Nx\g_mix_btnactions_tl{~\mix_pdflastobj:}
    }
  },
  jsaction .value_required:n = {true},

  unknown .code:n = {
    \msg_error:nnx{media9}{unknown~option}{\l_keys_key_tl}
  }
}

%create media buttons
\int_new:N\g_mix_mbtncnt_int
\NewDocumentCommand\mediabutton{O{}m}{%#1 options, #2 normal button text
  \mix_uriend:
  \group_begin:
  \mix_beginLTR:
  \leavevmode
  %reset various variables
  \tl_gclear:N\g_mix_overbtn_tl
  \tl_gclear:N\g_mix_downbtn_tl
  \tl_gclear:N\g_mix_btnactions_tl
  \tl_gclear:N\g_mix_tooltip_tl
  %process options
  \bool_gset_eq:NN\g_mix_btndraft_bool\g_mix_pkgdraft_bool
  \mix_uribegin: %treat URI characters correctly
  \keys_set:nn{media9/mbtndraft}{#1} %detect draft/final on first pass
  \bool_if:NF\g_mix_btndraft_bool{\keys_set:nn{media9/mbtn}{#1}}
  \mix_uriend:
  %normal button appearance
  %\hbox_set:Nn\l_mix_poster_box{#2}
  \sbox\l_mix_poster_box{#2}
  \tl_set:Nx\width {\dim_use:N\box_wd:N\l_mix_poster_box}
  \tl_set:Nx\height{\dim_use:N\box_ht:N\l_mix_poster_box}
  \tl_set:Nx\depth {\dim_use:N\box_dp:N\l_mix_poster_box}
  \bool_if:NTF\g_mix_btndraft_bool{\box_use:N\l_mix_poster_box}{
    \sbox\l_mix_poster_box{\bool_if:NTF\g_pbs_lscape_bool{\rotatebox{90}{
      \box_use:N\l_mix_poster_box}}{\box_use:N\l_mix_poster_box}}
    \mix_pdfxform:n{\l_mix_poster_box}
    \tl_set:Nx\g_mix_normalbtn_tl{\mix_pdflastxform:}
    %insert widget annotation
    \mix_pdfannot:nnnn{\width}{\height}{\depth}{
      /Subtype/Widget
      /T~(mbtn@\int_use:N\g_mix_mbtncnt_int)
      \tl_if_empty:NF\g_mix_tooltip_tl{/TU~(\g_mix_tooltip_tl)}
      /FT/Btn/Ff~65536
      \tl_if_empty:NTF\g_mix_downbtn_tl{/H/I}{/H/P}
      /AP~<<
        /N~\g_mix_normalbtn_tl
        \tl_if_empty:NF\g_mix_overbtn_tl{/R~\g_mix_overbtn_tl}
        \tl_if_empty:NF\g_mix_downbtn_tl{/D~\g_mix_downbtn_tl}
      >>
      /MK~<<
        /TP~1~/IF~<</S/A/FB~true/A~[0.0~0.0]>>
        /I~\g_mix_normalbtn_tl
        \tl_if_empty:NF\g_mix_overbtn_tl{/RI~\g_mix_overbtn_tl}
        \tl_if_empty:NF\g_mix_downbtn_tl{/IX~\g_mix_downbtn_tl}
      >>
      /A~<<
        /S/JavaScript/JS~(app.focusRect=false;)
        %sequence of actions to perform
        \tl_if_empty:NF\g_mix_btnactions_tl{/Next~[\g_mix_btnactions_tl]}
      >>
    }
    \mix_appendtofields:n{\mix_pdflastann:}
    \hbox_to_wd:nn{\width}{
      \vrule~width~\c_zero_dim~height~\height~depth~\depth\hss
    }
    \int_gincr:N\g_mix_mbtncnt_int
  }
  \mix_endLTR:
  \group_end:
}
\tl_set_eq:NN\l_mix_mediabutton_tl\mediabutton
\tl_set:Nn\mediabutton{\mix_uribegin:\l_mix_mediabutton_tl}