123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- import XStaticMesh from "./XStaticMesh.js"
- import EMeshType from "./enum/EMeshType.js"
- import Logger from "./Logger.js"
- import Stream from "./Stream.js";
- const logger = new Logger('Television')
- export default class XTelevision {
- constructor(scene, meshUrl, scenemanager, option) {
- E(this, "videoElement");
- E(this, "meshPath");
- E(this, "scene");
- E(this, "tvMeshs", []);
- E(this, "vAng");
- E(this, "videoMat");
- E(this, "videoTexture");
- E(this, "widthHeightScale");
- E(this, "fitMode");
- E(this, "_scenemanager");
- this.scene = scene
- this.meshPath = meshUrl
- this._scenemanager = scenemanager
- if (option != null) {
- const {vAng=0, widthHeightScale=-1, fitMode="fill"} = option;
- this.vAng = vAng,
- this.widthHeightScale = widthHeightScale,
- this.fitMode = fitMode
- }
- }
- set tvWidthHeightscale(e) {
- this.widthHeightScale = e
- }
- get tvWidthHeightscale() {
- return this.widthHeightScale
- }
- get tvFitMode() {
- return this.fitMode
- }
- set tvFitMode(e) {
- this.fitMode = e
- }
- setPlaySpeed(e) {
- this.videoElement != null && (this.videoElement.playbackRate = e)
- }
- getMesh() {
- return this.tvMeshs
- }
- createElement(e, t=!1) {
- const n = new Stream().el;
- return n.loop = t,
- n.autoplay = !0,
- n.src = e,
- n
- }
- async setUrl(e) {
- const {url, isLive: r=!1, poster: n=null, bLoop: o=!1, bMuted: a=!0} = e || {};
- if (typeof url != "string")
- return logger.error("[Engine] Tv setUrl Error, url must be string: ", url),
- Promise.reject(new XTvMediaUrlError("[Engine] url must be string"));
- if (this.videoElement) {
- this.videoElement.src = url,
- n != null && n.length > 0 && (this.videoElement.poster = n);
- const l = this.play();
- return "bMuted"in e && l !== void 0 && l.then(()=>{
- this.videoElement.muted = a
- }),
- this.videoElement.addEventListener("loadedmetadata", u=>{
- this.videoElement.videoWidth > 0
- ? this.videoMat.setFloat("mvWidthHeightScale", this.videoElement.videoWidth / this.videoElement.videoHeight)
- : this.videoMat.setFloat("mvWidthHeightScale", 16 / 9)
- }),
- Promise.resolve(this)
- }
- const s = this.createElement(url, o);
- n != null && n.length > 0 && (s.poster = n)
- return this.setVideo(s, r).then(()=>{
- const l = this.videoElement && this.videoElement.play();
- "bMuted"in e && l !== void 0 && l.then(()=>{
- this.videoElement.muted = a
- })
- }).catch(l=>{
- logger.error("[Engine] setUrl error! " + l),
- new XTvMediaUrlError("[Engine] setUrl error! " + l)
- })
- }
- setCurrentTime(e) {
- if (!this.videoElement) {
- logger.warn("[Engine] The television is not been initialize succesfully");
- return
- }
- const {currentTime: t} = e;
- if (typeof t != "number") {
- logger.warn("[Engine] video currentTime must be number");
- return
- }
- this.videoElement.currentTime = t / 1e3
- }
- getCurrentTime() {
- return this.videoElement ? this.videoElement.currentTime * 1e3 : -1
- }
- play() {
- return logger.info("[Engine] Play television"),
- this.toggle(!0),
- this.videoElement ? this.videoElement.play() : Promise.resolve()
- }
- pause() {
- var e;
- return logger.info("[Engine] Pause television"),
- (e = this.videoElement) == null ? void 0 : e.pause()
- }
- stop() {
- logger.info("[Engine] Stop television"),
- this.pause(),
- setTimeout(()=>{
- this.setCurrentTime({
- currentTime: 0
- })
- }
- ),
- this.toggle(!1)
- }
- toggle(e) {
- logger.info(`[Engine] Set Tv visibility = ${e}`);
- for (let t = 0; t < this.tvMeshs.length; ++t)
- e == !0 ? this.tvMeshs[t].show() : this.tvMeshs[t].hide()
- }
- getVideoMat() {
- return this.videoMat
- }
- changeTvFitMode() {
- this.fitMode == "contain" ? (this.widthHeightScale < 0 && (this.widthHeightScale = 2.4),
- this.videoMat.setFloat("tvWidthHeightScale", this.widthHeightScale),
- this.videoMat.setFloat("bforceforceKeepContent", 1)) : this.fitMode == "cover" ? (this.widthHeightScale < 0 && (this.widthHeightScale = this.calWidthHeightScale()),
- this.videoMat.setFloat("tvWidthHeightScale", this.widthHeightScale),
- this.videoMat.setFloat("bforceforceKeepContent", -1)) : this.videoMat.setFloat("tvWidthHeightScale", -1)
- }
- async setVideo(e, t=!1, r=!0)
- {
- return this.tvMeshs.length != 0 ? (
- logger.warn(`[Engine] Set Video. length!=0, mesh: ${this.meshPath}, src: ${e.src}`),
- new Promise((n,o)=>
- {
- if (!(e instanceof HTMLVideoElement))
- return logger.error("[Engine] Error, param of setVideo must be a HTMLVideoElement"),
- o(new XTvVideoElementError("[Engine] param of setVideo must be a HTMLVideoElement"));
- this.videoElement = e,
-
- r == !1
- && (t == !1 || checkOS().isIOS)
- && e.crossOrigin !== "anonymous"
- && (e.crossOrigin = "anonymous", e.load()),
- this.videoElement.addEventListener("loadedmetadata", a=>{
- this.videoElement.videoWidth > 0 ? this.videoMat.setFloat("mvWidthHeightScale", this.videoElement.videoWidth / this.videoElement.videoHeight) : this.videoMat.setFloat("mvWidthHeightScale", 16 / 9)
- }),
- this.videoTexture.updateURL(this.videoElement.src),
- n(this)
- })
- ) : (
- logger.warn(`[Engine] Set Video. length==0, mesh: ${this.meshPath}, src: ${e.src}`),
- this.meshPath == ""
- ? (
- logger.error("[Engine] Error, television meshPath is empty."),
- Promise.reject(new XTvVideoElementError("[Engine] Error, television meshPath is empty."))
- )
- : this._scenemanager.urlTransformer(this.meshPath).then(n => new Promise((o,a) =>
- e instanceof HTMLVideoElement
- ? (
- this.videoElement = e,
- r == !1
- && (t == !1 || checkOS().isIOS)
- && e.crossOrigin !== "anonymous"
- && (e.crossOrigin = "anonymous", e.load()),
- BABYLON.SceneLoader.LoadAssetContainerAsync("", n, this.scene, null, ".glb").then(s=>{
- for (let u = s.materials.length - 1; u >= 0; --u) s.materials[u].dispose();
- this.videoTexture = new BABYLON.VideoTexture("videoTex_" + Date.now(),e,this.scene,!1,!0,void 0,{
- autoPlay: !0,
- autoUpdateTexture: !0,
- muted: !0
- }),
- this.videoTexture.vAng = this.vAng,
- this.videoMat = new BABYLON.ShaderMaterial("videoMat_" + Date.now(),this.scene,{
- vertexSource: tvVertex,
- fragmentSource: tvFragment
- },{
- attributes: ["uv", "position"],
- uniforms: ["view", "projection", "worldViewProjection", "world"]
- }),
- this.videoMat.setTexture("texture_video", this.videoTexture),
- this.videoMat.setFloat("tvWidthHeightScale", -1),
- this.videoMat.setFloat("mvWidthHeightScale", 16 / 9),
- this.videoMat.setFloat("bforceforceKeepContent", -1),
- this.videoMat.backFaceCulling = !1,
- this.videoMat.sideOrientation = BABYLON.Mesh.FRONTSIDE,
- this.videoElement.addEventListener("loadedmetadata", u=>{
- this.videoElement.videoWidth > 0
- ? this.videoMat.setFloat("mvWidthHeightScale", this.videoElement.videoWidth / this.videoElement.videoHeight)
- : this.videoMat.setFloat("mvWidthHeightScale", 16 / 9)
- });
- const tvMeshs = [];
- for (let u = 0; u < s.meshes.length; ++u)
- s.meshes[u].visibility = 1,
- s.meshes[u].isPickable = !0,
- s.meshes[u].checkCollisions = !1,
- s.meshes[u].material = this.videoMat,
- "hasVertexAlpha"in s.meshes[u] && (s.meshes[u].hasVertexAlpha = !1),
- this.scene.addMesh(s.meshes[u]),
- tvMeshs.push(new XStaticMesh({
- id: s.meshes[u].id,
- mesh: s.meshes[u],
- xtype: EMeshType.Tv
- }));
- this.changeTvFitMode(),
- this.tvMeshs = tvMeshs,
- this.toggle(!0),
- o(this)
- }).catch(s=>{
- logger.error("[Engine] setVideo: create Tv by input mesh error! " + s),
- a(new XTvModelError("[Engine] setVideo: create Tv by input mesh error! " + s))
- })
- )
- : a(new XTvVideoElementError("[Engine] param of setVideo must be a HTMLVideoElement"))
- ))
- )
- }
- async setSameVideo(e, t="") {
- return e == null || e == null ? (logger.error("[Engine] setSameVideo: input material is null or undefined "),
- Promise.reject(new XTvModelError("[Engine] setSameVideo input material is null or undefined !"))) : this.tvMeshs.length != 0 && t == "" ? (logger.warn(`[Engine] Set mirror video. length!=0, mesh: ${this.meshPath}`),
- new Promise((r,n)=>{
- try {
- this.videoMat = e,
- this.tvMeshs.forEach(o=>{
- o.setMaterial(e)
- }
- ),
- this.changeTvFitMode(),
- r(this)
- } catch (o) {
- logger.error("[Engine] setSameVideo: create Tv by input mesh error! " + o),
- n(new XTvModelError("[Engine] create Tv by input mesh error! " + o))
- }
- }
- )) : (t != "" && (this.meshPath = t,
- this.widthHeightScale = -1),
- this.meshPath == "" ? (logger.error("[Engine] Error, setSameVideo television meshPath is empty."),
- Promise.reject(new XTvVideoElementError("[Engine] Error, setSameVideo television meshPath is empty."))) : (logger.warn(`[Engine] Set mirror video. length==0, mesh: ${this.meshPath}`),
- this._scenemanager.urlTransformer(this.meshPath).then(r=>new Promise((n,o)=>(this.videoMat = e,
- e != null && e.getActiveTextures()[0] && (this.videoElement = e == null ? void 0 : e.getActiveTextures()[0].video),
- BABYLON.SceneLoader.LoadAssetContainerAsync("", r, this.scene, null, ".glb").then(a=>{
- for (let l = a.materials.length - 1; l >= 0; --l)
- a.materials[l].dispose();
- const s = [];
- for (let l = 0; l < a.meshes.length; ++l)
- a.meshes[l].visibility = 0,
- a.meshes[l].isPickable = !0,
- a.meshes[l].checkCollisions = !1,
- a.meshes[l].material = this.videoMat,
- "hasVertexAlpha"in a.meshes[l] && (a.meshes[l].hasVertexAlpha = !1),
- this.scene.addMesh(a.meshes[l]),
- s.push(new XStaticMesh({
- id: a.meshes[l].id,
- mesh: a.meshes[l],
- xtype: EMeshType.Tv
- }));
- t != "" && this.cleanTv(!1, !1),
- this.tvMeshs = s,
- this.changeTvFitMode(),
- n(this)
- }
- ).catch(a=>{
- logger.error("[Engine] setSameVideo: create Tv by input mesh error! " + a),
- o(new XTvModelError("[Engine] create Tv by input mesh error! " + a))
- }
- ))))))
- }
- async changeTvModel(e="") {
- return e != "" && (this.meshPath = e,
- this.widthHeightScale = -1),
- this.meshPath == "" ? (logger.error("[Engine] Error,changeTvModel television meshPath is empty."),
- Promise.reject(new XTvVideoElementError("[Engine] Error, changeTvModel television meshPath is empty."))) : this.videoMat == null || this.videoMat == null ? (logger.error("[Engine] changeTvModel: videoMat is null or undefined! "),
- Promise.reject(new XTvModelError("[Engine] changeTvModel: videoMat is null or undefined!"))) : this._scenemanager.urlTransformer(this.meshPath).then(t=>new Promise((r,n)=>BABYLON.SceneLoader.LoadAssetContainerAsync("", t, this.scene, null, ".glb").then(o=>{
- for (let s = o.materials.length - 1; s >= 0; --s)
- o.materials[s].dispose();
- const a = [];
- for (let s = 0; s < o.meshes.length; ++s)
- o.meshes[s].visibility = 0,
- o.meshes[s].isPickable = !0,
- o.meshes[s].checkCollisions = !1,
- o.meshes[s].material = this.videoMat,
- "hasVertexAlpha"in o.meshes[s] && (o.meshes[s].hasVertexAlpha = !1),
- this.scene.addMesh(o.meshes[s]),
- a.push(new XStaticMesh({
- id: o.meshes[s].id,
- mesh: o.meshes[s],
- xtype: EMeshType.Tv
- }));
- e != "" && this.cleanTv(!1, !1),
- this.tvMeshs = a,
- this.changeTvFitMode(),
- r(this)
- }
- ).catch(o=>{
- logger.error("[Engine] changeTvModel: create Tv by input mesh error! " + o),
- n(new XTvModelError("[Engine] changeTvModel: create Tv by input mesh error! " + o))
- }
- )))
- }
- calWidthHeightScale() {
- const e = [1e5, 1e5, 1e5]
- , t = [-1e5, -1e5, -1e5];
- for (let a = 0; a < this.tvMeshs.length; ++a)
- if (this.tvMeshs[a].mesh.name != "__root__") {
- const s = this.tvMeshs[a].mesh.getBoundingInfo().boundingBox.vectorsWorld;
- for (let l = 0; l < s.length; ++l)
- e[0] > s[l].x && (e[0] = s[l].x),
- e[1] > s[l].y && (e[1] = s[l].y),
- e[2] > s[l].z && (e[2] = s[l].z),
- t[0] < s[l].x && (t[0] = s[l].x),
- t[1] < s[l].y && (t[1] = s[l].y),
- t[2] < s[l].z && (t[2] = s[l].z);
- break
- }
- const r = t[0] - e[0]
- , n = t[1] - e[1]
- , o = t[2] - e[2];
- return Math.sqrt(r * r + o * o) / Math.abs(n)
- }
- cleanTv(e=!1, t=!0) {
- logger.warn("[Engine] cleanTV");
- for (let r = 0; r < this.tvMeshs.length; ++r)
- this.tvMeshs[r].dispose(e, t);
- this.tvMeshs = [],
- this.meshPath = ""
- }
- }
|