"use strict";
var _ = require("lodash");
var Condicio = require("condicio");
var View3D = require("./View3D/View3D.js"),
ViewPID = require("./ViewPID/ViewPID.js"),
Session = require("./Session.js"),
Viewpoint = require("./View3D/Viewpoint.js"),
Utility = require("./Utility.js"),
NetworkProtocol = require("./NetworkProtocol.js"),
semver = require("semver"),
ParamValidation = require("./ParamValidation.js"),
RoamerFactory = require("./View3D/RoamerFactory.js"),
Error = require("./Error.js"),
jQuery = require("jquery"),
Debug = require("./Debug.js");
var NetworkError = Error.NetworkError;
var InvalidArgumentError = Error.InvalidArgumentError;
var VersioningError = Error.VersioningError;
/**
* @class Factory
*
* 创建PID和三维显示窗口
*
* 应用不应该构建,应该通过createFactory创建得到
*
*/
function Factory(session, enableSSL, proxyUri) {
this.session = session;
this.objectID = "Factory";
this.enableSSL = enableSSL;
this.proxyUri = proxyUri;
};
/**
* 释放窗口资源
*
* @param {View3D\ViewPID[]} views 待释放的窗口资源集合
*/
Factory.prototype.releaseView = function (views) {
var objectIDs = [];
for (var i = 0; i < views.length; ++i) {
if(Condicio.isType(views[i], View3D) || Condicio.isType(views[i], ViewPID)){
views[i].release();
objectIDs.push(views[i].objectID);
}
else{
throw "The type of views awaiting release must be 'View3D' or 'ViewPID'";
}
}
this.session.request(this.objectID, "releaseView", { objectIDs: objectIDs });
};
/**
* <a href="https://fulongtech.atlassian.net/wiki/spaces/RenderingTech/pages/1148354569/5.8.0">参数具体信息说明</a>
* 创建3D显示窗口
* @param {HTMLElement} elem 父元素
* @param {Function} callback 创建完成后回调
* @param {Error} callback.err 创建失败返回错误
* @param {View3D.View3D} callback.view3D 创建成功后返回显示窗口
* @param {Number} mode 三维传输模式
* 0: Compatible表示兼容模式(兼容IE,chrome)
* 1: DataSaver表示省流模式,带宽占用低(只支持chrome)
* @param {Number} [option] 3D显示窗口配置参数
* @param {Number} [option.maxFPS = 20] 最大帧率
* @param {Number} [option.LODScale = 1] 可控制场景中模型的加载数量
* @param {Number} [option.maxPagedLODNumber = 500] 最大加载PagedLOD数量
* @param {Number} [option.enableTransparency = false] 模型颜色带透明位的是否显示为不透明
* @param {Number} [option.loadDurMoving = true] 场景移动过程中是否允许加载模型
* @param {Number} [option.maxFrameTime = 0.1] 渲染一帧允许的最大时间
* @param {Number} [option.computeNearFarMode = 0] 计算远近平面的方式
* 0: PrecisionMode表示精准模式
* 1: FastMode表示快速模式
* FastMode可以解决某些视角下漫游会卡的问题,但可能导致模型闪面
*/
Factory.prototype.createView3D = function (elem, callback, mode, option) {
Condicio.checkNotNull(elem,"HTMLElement parameter cannot be null");
Condicio.checkNotUndefined(elem, "HTMLElement parameter cannot be undefined");
Condicio.checkIsFunction(callback, "The type of callback must be 'Function'!");
mode = mode || 0;
Condicio.checkIsNumber(mode, "The type of mode must be 'Number'!");
Condicio.checkArgument(mode == 1 || mode == 0, "The mode must: 0 or 1");
var callbackID = Utility.genGUID();
var _this = this;
var callbackWrapper = function (error, result) {
if (!error){
var callbackResult = function (err, view3D) {
if(err)
callback(err, null);
else{
var roamer1 = view3D.RoamerFactory.createFreeModeRoamer();
view3D.swapRoamer(roamer1);
callback(null, view3D);
}
}
new View3D(_this.session, elem, result, mode, _this.enableSSL, _this.proxyUri, callbackResult);
}
else
callback(error, null);
};
this.session.registerCallback(callbackID, callbackWrapper, "createView3D");
var defaultConfig = {
maxFPS : 20,
LODScale : 1,
maxPagedLODNumber : 500,
enableTransparency : false,
loadDurMoving : true,
maxFrameTime : 0.1,
computeNearFarMode : 0,
};
var newConfig = jQuery.extend({}, defaultConfig, option);
ParamValidation.checkIsView3DConfig(newConfig);
var params ={
callbackID: callbackID,
mode : mode,
config : newConfig
};
this.session.request(this.objectID, "createView3D", params);
};
/**
* 创建PID显示窗口
*
* @param {HTMLElement} elem 父元素
* @param {Function} callback 创建完成后回调
* @param {Error} callback.err 创建失败返回错误
* @param {ViewPID.ViewPID} callback.viewPID 创建成功后返回显示窗口
*/
Factory.prototype.createViewPID = function (elem, callback) {
Condicio.checkNotNull(elem,"HTMLElement parameter cannot be null");
Condicio.checkNotUndefined(elem, "HTMLElement parameter cannot be undefined");
Condicio.checkIsFunction(callback, "The type of callback must be 'Function'!");
var callbackID = Utility.genGUID();
var _this = this;
var callbackWrapper = function (error, result) {
if (!error)
callback(null, new ViewPID(_this.session, elem, result.viewID, _this.enableSSL, _this.proxyUri));
else
callback(error, null);
};
this.session.registerCallback(callbackID, callbackWrapper, "createViewPID");
this.session.request(this.objectID, "createViewPID", {callbackID: callbackID });
};
var hasProxy = function(options, recvPack){
if(options.server.ip !== "localhost"
&&(options.server.ip !== recvPack.body.result.ip
|| options.server.port !== recvPack.body.result.port)){
return true;
}
return false;
};
/**
* @member Global.createFactory
* 创建服务器组件工厂
*
* @param {Object} options 创建工厂参数
* @param {Object} options.server 服务器连接信息
* @param {Boolean} [options.server.useSSL=false] 与服务器通信是否使用加密协议(HTTPS),默认为HTTP
* @param {String} options.server.ip 服务器IP地址
* @param {String} options.server.port 服务器连接端口号
* @param {String} [options.server.userName] 当前登录的用户名(BRS下载文件需要用户验证时需填)
* @param {String} [options.server.language] 当前系统语言,默认中文
* (中文:zh_CN,英文:en_US,输入非中文默认都是英文)
* @param {Function} options.errorHandler 创建完成以后,服务器运行过程发生错误或者连接意外断开回调
* @param {Error} options.errorHandler.err 发生错误时候传出错误
* err{NetworkError} 网络断开
* err{InvalidArgumentError} 调用方法时候,请求的某些对象不存在、请求的方法没有定义
* @param {Function} callback 创建完成回调
* @param {Error} callback.err 创建失败返回错误
* err{NetworkError} 网络连接失败
* err{VersioningError} 版本协商失败
* err{SystemError} 启动渲染服务失败
* @param {Factory} callback.factory 创建成功返回工厂
*/
function createFactory(options, callback) {
Condicio.checkIsObject(options, "The type of options must be 'Object'!");
Condicio.checkIsObject(options.server, "The type of server must be 'Object'!");
Condicio.checkIsString(options.server.ip, "The type of server ip must be 'String'!");
Condicio.checkIsString(options.server.port, "The type of server port must be 'String'!");
Condicio.checkIsFunction(options.errorHandler, "The type of error-callbck must be 'Function'!");
Condicio.checkIsFunction(callback, "The type of complete-callback must be 'Function'!");
var defaultProtocol = "ws://";
options.server.useSSL = options.server.useSSL || false;
if(options.server.useSSL){
defaultProtocol = "wss://";
}
options.server.userName = options.server.userName || "";
Condicio.checkIsString(options.server.userName, "The type of server userName must be 'String'!");
options.server.language = options.server.language || "zh_CN";
Condicio.checkIsString(options.server.language, "The type of server language must be 'String'!");
var listenerUrl = defaultProtocol + options.server.ip + ":" + options.server.port + "/brs"
+ "?vicVersion=" + NetworkProtocol.VersionNumber.CurrentVIC
+ "&supportBRSMinimumVersion=" + NetworkProtocol.VersionNumber.SupportBRSMinimum
+ "&userName=" + options.server.userName
+ "&language=" + options.server.language;
var ws = new WebSocket(listenerUrl);
ws.onmessage = function(ev){
var recvPack = new NetworkProtocol.Package;
recvPack.fromString(ev.data);
switch (recvPack.type) {
case NetworkProtocol.PackageType.SessionReady: {
var proxyUri = ""; //用于之后图片请求是否使用代理服务器
if(hasProxy(options, recvPack)){
proxyUri = recvPack.body.result.ip + ":" + recvPack.body.result.port;
}
var rendererID = recvPack.body.result.rendererID;
var session = new Session(ws, options.server.ip, options.server.port, options.errorHandler, rendererID);
callback(null, new Factory(session, options.server.useSSL, proxyUri));
break;
}
case NetworkProtocol.PackageType.Error: {
callback(Error.genError(recvPack.body.error));
break;
}
}
};
ws.onclose = function(){
callback(new NetworkError("Can't connect server, please check if the server address is correct!"));
};
};
/**
* @member Global.releaseFactory
* 释放服务器组件工厂
*
* @param {Factory[]} factorys 需要释放的工厂集合
*/
function releaseFactory(factorys) {
for (var i = 0; i < factorys.length; ++i) {
if(Condicio.isType(factorys[i], Factory)){
factorys[i].session.close();
}
else{
throw "The type of factorys awaiting release must be 'Factory'";
}
}
};
exports.createFactory = createFactory;
exports.releaseFactory = releaseFactory;
exports.Viewpoint = Viewpoint;
exports.Debug = Debug;