exports.get_text_sync = function(asset_uri) { // check in cache if (_loaded_assets[asset_uri]) return _loaded_assets[asset_uri]; if (cfg_ldr.prevent_caching) var filepath = asset_uri + m_version.timestamp(); else var filepath = asset_uri; var req = new XMLHttpRequest(); req.overrideMimeType("text/plain"); // to prevent "not well formed" error req.open("GET", filepath, false); req.send(null); if (req.status == 200 || req.status == 0) { var resp_text = req.responseText; if (resp_text.length) { // save in cache _loaded_assets[asset_uri] = resp_text; return resp_text; } else m_util.panic("Error XHR: responce is empty, GET " + asset_uri); } else { m_util.panic("Error XHR: " + req.status + ", GET " + asset_uri); } }
function remove_sensor_manifold(obj, id) { obj = obj || _global_object; var manifolds = obj.sensor_manifolds; if (!manifolds) return; var manifolds_arr = obj.sensor_manifolds_arr; if (id) { var manifold = manifolds[id]; if (manifold) { var sensors = manifold.sensors; for (var i = 0; i < sensors.length; i++) { var sensor = sensors[i]; var sens_users = get_sensor_users(sensor, _sensors_cache, _manifolds_cache); if (sens_users.length == 1) { deactivate_sensor(sensor); var sens_ind = _sensors_cache.indexOf(sensor); if (sens_ind > -1) { _sensors_cache.splice(sens_ind, 1); _manifolds_cache.splice(sens_ind, 1); } else m_util.panic("Sensors cache is corrupted"); } else if (sens_users.length > 1) sens_users.splice(sens_users.indexOf(manifold, 1)); } delete manifolds[id]; var man_index = manifolds_arr.indexOf(manifold); if (man_index > -1) manifolds_arr.splice(man_index, 1); else m_util.panic("Incorrect manifolds array"); // remove from objects if manifolds have 0 sensors if (!Object.getOwnPropertyNames(manifolds).length) remove_from_objects(obj); } } else { // make a copy to ensure reliable results var removed_ids = []; for (var id in manifolds) removed_ids.push(id); for (var i = 0; i < removed_ids.length; i++) remove_sensor_manifold(obj, removed_ids[i]); } _manifolds_updated = true; }
exports.remove_sensor_manifold = function(obj, id) { obj = obj || _global_object; var manifolds = obj._sensor_manifolds; if (!manifolds) return; var manifolds_arr = obj._sensor_manifolds_arr; if (id) { var manifold = manifolds[id]; if (manifold) { var sensors = manifold.sensors; for (var j = 0; j < sensors.length; j++) if (get_sensor_users_num(sensors[j], _objects) === 1) { remove_sensor(sensors[j], _sensors); } delete manifolds[id]; var man_index = manifolds_arr.indexOf(manifold); if (man_index > -1) manifolds_arr.splice(man_index, 1); else m_util.panic("Incorrect manifolds array"); // remove from objects if manifolds have 0 sensors if (!Object.getOwnPropertyNames(manifolds).length) { remove_from_objects(obj); } } return; } // remove all manifolds if id is null for (var id in manifolds) { var manifold = manifolds[id]; var sensors = manifold.sensors; for (var j = 0; j < sensors.length; j++) if (get_sensor_users_num(sensors[j], _objects) === 1) { remove_sensor(sensors[j], _sensors); } delete manifolds[id]; var man_index = manifolds_arr.indexOf(manifold); if (man_index > -1) manifolds_arr.splice(man_index, 1); else m_util.panic("Incorrect manifolds array"); } remove_from_objects(obj); _manifolds_updated = true; }
exports.check_gl = function(msg) { if (!_check_errors) return; var error = _gl.getError(); if (error == _gl.NO_ERROR) return; if (error in ERRORS) m_util.panic("GL Error: " + error + ", gl." + ERRORS[error] + " (" + msg + ")"); else m_util.panic("Unknown GL error: " + error + " (" + msg + ")"); }
function assert_structure(obj1, obj2) { if (typeof obj1 != typeof obj2) m_util.panic("Structure assertion failed: incompatible types"); for (var i in obj1) { if (!(i in obj2)) m_util.panic("Structure assertion failed: missing key in the first object: " + i); } for (var i in obj2) { if (!(i in obj1)) m_util.panic("Structure assertion failed: missing key in the second object: " + i); if (typeof obj1[i] != typeof obj2[i]) m_util.panic("Structure assertion failed: incompatible types for key " + i); } }
function request_video(asset) { if (asset.request != "GET") { m_util.panic("Unsupported request type for video element"); } var video = document.createElement("video"); video.muted = true; // HACK: allow crossOrigin for mobile devices (Android Chrome bug) if (cfg_def.allow_cors || cfg_def.is_mobile_device) video.crossOrigin = "Anonymous"; video.addEventListener("loadeddata", function() { video.removeEventListener("error", video_error_event, false); if (asset.state != ASTATE_HALTED) { asset.asset_cb(video, asset.id, asset.type, asset.url, asset.param); asset.state = ASTATE_RECEIVED; } }, false); function video_error_event(e) { if (asset.state != ASTATE_HALTED) { asset.asset_cb(null, asset.id, asset.type, asset.url); m_print.error("could not load video: " + asset.url, asset.param); asset.state = ASTATE_RECEIVED; } } video.addEventListener("error", video_error_event, false); var bd = get_built_in_data(); if (bd && asset.url in bd) { if (bd[asset.url]) { var vid_mime_type = get_video_mime_type(asset.url); video.src = "data:" + vid_mime_type + ";base64," + bd[asset.url]; if (asset.state != ASTATE_HALTED) video.addEventListener("loadeddata", function() { asset.asset_cb(video, asset.id, asset.type, asset.url, asset.param); asset.state = ASTATE_RECEIVED; }, false); } else { if (m_compat.is_ie11()) { var e = document.createEvent("CustomEvent"); e.initCustomEvent("error", false, false, null); } else var e = new CustomEvent("error"); video.dispatchEvent(e); } } else { video.src = asset.url; if (cfg_def.is_mobile_device) video.load(); } if (cfg_def.mobile_firefox_media_hack) { video.autoplay = true; video.pause(); } // HACK: workaround for some garbage collector bug setTimeout(function() {video.some_prop_to_prevent_gc = 1}, 10000); }
function request_seq_video(asset) { if (asset.request != "GET") { m_util.panic("Unsupported request type for seq video element"); } var bd = get_built_in_data(); if (bd && asset.url in bd) var req = new FakeHttpRequest(); else var req = new XMLHttpRequest(); if (asset.post_type == null && asset.post_data == null) { req.open("GET", asset.url, true); } else { req.open("POST", asset.url, true); switch (asset.post_type) { case exports.APT_TEXT: req.setRequestHeader('Content-type', 'text/plain'); break; case exports.APT_JSON: req.setRequestHeader('Content-type', 'application/json'); break; } } req.responseType = "arraybuffer"; function load_cb(images) { asset.asset_cb(images, asset.id, asset.type, asset.url, asset.param); asset.state = ASTATE_RECEIVED; } req.onreadystatechange = function() { if (asset.state != ASTATE_HALTED) if (req.readyState == 4) { if (req.status == 200 || req.status == 0) { var response = req.response; if (response) parse_seq_video_file(response, load_cb); else { asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); m_print.error("empty responce when trying to get " + asset.url); asset.state = ASTATE_RECEIVED; } } else { asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); m_print.error(req.status + " when trying to get " + asset.url); asset.state = ASTATE_RECEIVED; } } }; req.addEventListener("progress", function(e) { // compute progress information if total size is known if (e.lengthComputable) asset.progress_cb(e.loaded / e.total); }, false); req.send(asset.post_data); }
exports.create_sensor_manifold = function(obj, id, type, sensors, logic_fun, callback, callback_param) { obj = obj || _global_object; obj._sensor_manifolds = obj._sensor_manifolds || {}; obj._sensor_manifolds_arr = obj._sensor_manifolds_arr || []; var manifolds = obj._sensor_manifolds; var manifolds_arr = obj._sensor_manifolds_arr; var old_manifold = manifolds[id]; if (old_manifold) { var sensors = old_manifold.sensors; for (var i = 0; i < sensors.length; i++) if (get_sensor_users_num(sensors[i], _objects) === 1) { remove_sensor(sensors[i], _sensors); } var man_index = manifolds_arr.indexOf(old_manifold); if (man_index > -1) manifolds_arr.splice(man_index, 1); else m_util.panic("Incorrect manifolds array"); } var manifold = { id: id, type: type, sensors: sensors.slice(0), logic_fun: logic_fun, // cache for logic function sensor_values: new Array(sensors.length), callback: callback, callback_param: callback_param, last_pulse: -1, // for LEVEL control type last_logic_result: 0, update_counter: -1 }; manifolds[id] = manifold; manifolds_arr.push(manifold); if (_objects.indexOf(obj) == -1) _objects.push(obj); append_sensors(manifold.sensors); _manifolds_updated = true; }
function request_assets(queue) { var req_cnt = 0; for (var i = 0; i < queue.length; i++) { var asset = queue[i]; if (asset.state === ASTATE_REQUESTED) req_cnt++; // check requests limit if (req_cnt >= cfg_ldr.max_requests) break; // pass recently enqueued if (asset.state !== ASTATE_ENQUEUED) continue; asset.state = ASTATE_REQUESTED; req_cnt++; switch (asset.type) { case exports.AT_ARRAYBUFFER: request_arraybuffer(asset, "arraybuffer"); break; case exports.AT_JSON: request_arraybuffer(asset, "json"); break; case exports.AT_TEXT: request_arraybuffer(asset, "text"); break; case exports.AT_AUDIOBUFFER: request_audiobuffer(asset); break; case exports.AT_IMAGE_ELEMENT: request_image(asset); break; case exports.AT_AUDIO_ELEMENT: request_audio(asset); break; case exports.AT_VIDEO_ELEMENT: request_video(asset); break; case exports.AT_SEQ_VIDEO_ELEMENT: request_seq_video(asset); break; default: m_util.panic("Wrong asset type: " + asset.type); break; } } }
function request_audiobuffer(asset) { if (asset.request != "GET") { m_util.panic("Unsupported request type for audio buffer"); } var bd = get_built_in_data(); if (bd && asset.url in bd) var req = new FakeHttpRequest(); else var req = new XMLHttpRequest(); req.open("GET", asset.url, true); req.responseType = "arraybuffer"; req.onreadystatechange = function() { if (asset.state != ASTATE_HALTED) if (req.readyState == 4) { if (req.status == 200 || req.status == 0) { var response = req.response; if (response) { var decode_cb = function(audio_buffer) { asset.asset_cb(audio_buffer, asset.id, asset.type, asset.url, asset.param); asset.state = ASTATE_RECEIVED; } var fail_cb = function() { asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); m_print.error("failed to decode " + asset.url); asset.state = ASTATE_RECEIVED; } m_sfg.decode_audio_data(response, decode_cb, fail_cb); } else { asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); m_print.error("empty responce when trying to get " + asset.url); asset.state = ASTATE_RECEIVED; } } else { asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); m_print.error(req.status + " when trying to get " + asset.url); asset.state = ASTATE_RECEIVED; } } }; req.send(asset.post_data); }
function request_image(asset) { if (asset.request != "GET") { m_util.panic("Unsupported request type for image element"); } var image = document.createElement("img"); if (cfg_def.allow_cors) image.crossOrigin = "Anonymous"; image.onload = function() { if (asset.state != ASTATE_HALTED) { asset.asset_cb(image, asset.id, asset.type, asset.url, asset.param); asset.state = ASTATE_RECEIVED; } }; image.addEventListener("error", function() { if (asset.state != ASTATE_HALTED) { asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); m_print.error("could not load image: " + asset.url); asset.state = ASTATE_RECEIVED; } }, false); var bd = get_built_in_data(); if (bd && asset.url in bd) { if (bd[asset.url]) { var img_mime_type = get_image_mime_type(asset.url); image.src = "data:" + img_mime_type + ";base64," + bd[asset.url]; } else { if (m_compat.is_ie11()) { var e = document.createEvent("CustomEvent"); e.initCustomEvent("error", false, false, null); } else var e = new CustomEvent("error"); image.dispatchEvent(e); } } else image.src = asset.url; }
exports.get_screen_scenes = function() { m_util.panic("get_screen_scenes() deprecated"); }
exports.set_light_direction = function() { m_util.panic("set_light_direction() deprecated, use lights module instead"); }
function request_audio(asset) { if (asset.request != "GET") { m_util.panic("Unsupported request type for audio element"); } var audio = document.createElement("audio"); if (cfg_def.allow_cors || cfg_def.cors_chrome_hack) audio.crossOrigin = "Anonymous"; audio.addEventListener("loadeddata", function() { if (asset.state != ASTATE_HALTED) { asset.asset_cb(audio, asset.id, asset.type, asset.url, asset.param); asset.state = ASTATE_RECEIVED; } }, false); audio.addEventListener("error", function() { if (asset.state != ASTATE_HALTED) { asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); m_print.error("could not load sound: " + asset.url); asset.state = ASTATE_RECEIVED; } }, false); audio.addEventListener("stalled", function() { if (asset.state != ASTATE_HALTED) { asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); m_print.error("could not load sound: " + asset.url); asset.state = ASTATE_RECEIVED; } }, false); var bd = get_built_in_data(); if (bd && asset.url in bd) { if (bd[asset.url]) { var snd_mime_type = get_sound_mime_type(asset.url); audio.src = "data:" + snd_mime_type + ";base64," + bd[asset.url]; if (asset.state != ASTATE_HALTED) { asset.asset_cb(audio, asset.id, asset.type, asset.url, asset.param); asset.state = ASTATE_RECEIVED; } } else { if (m_compat.is_ie11()) { var e = document.createEvent("CustomEvent"); e.initCustomEvent("error", false, false, null); } else var e = new CustomEvent("error"); audio.dispatchEvent(e); } } else { audio.src = asset.url; if (cfg_def.is_mobile_device) audio.load(); } if (cfg_def.mobile_firefox_media_hack) { audio.autoplay = true; audio.pause(); } // HACK: workaround for some garbage collector bug setTimeout(function() {audio.some_prop_to_prevent_gc = 1}, 5000); }
/** * 1 - positive pulse * -1 - negative pulse * 0 - no pulse */ function manifold_gen_pulse(manifold) { var pulse = 0; switch (manifold.type) { case exports.CT_POSITIVE: var logic_result = manifold_logic_result(manifold); if (logic_result) pulse = 1; else pulse = 0; break; case exports.CT_CONTINUOUS: var last_pulse = manifold.last_pulse; var logic_result = manifold_logic_result(manifold); if (logic_result) { pulse = 1; manifold.last_pulse = 1; } else if (last_pulse == 1) { pulse = -1; manifold.last_pulse = -1; } else pulse = 0; break; case exports.CT_TRIGGER: var last_pulse = manifold.last_pulse; var logic_result = manifold_logic_result(manifold); if (logic_result && last_pulse == -1) { pulse = 1; manifold.last_pulse = 1; } else if (!logic_result && last_pulse == 1) { pulse = -1; manifold.last_pulse = -1; } else pulse = 0; break; case exports.CT_SHOT: var last_pulse = manifold.last_pulse; var logic_result = manifold_logic_result(manifold); if (logic_result && last_pulse == -1) { pulse = 1; manifold.last_pulse = 1; } else if (!logic_result && last_pulse == 1) { // give no ouput, but register negative pulse pulse = 0; manifold.last_pulse = -1; } else pulse = 0; break; case exports.CT_LEVEL: // ignore previous pulses var logic_result = manifold_logic_result(manifold); if (manifold.last_logic_result != logic_result) { pulse = 1; manifold.last_logic_result = logic_result; } else pulse = 0; break; case exports.CT_CHANGE: // ignore previous pulses and logic result var sensors = manifold.sensors; var last_values = manifold.last_sensor_values; for (var i = 0; i < sensors.length; i++) { var value = sensors[i].value; if (!pulse && value != last_values[i]) pulse = 1; last_values[i] = value; } break; default: m_util.panic("Wrong sensor manifold type: " + manifold.type); break; } return pulse; }
exports.get_bpy_world = function(world_name) { m_util.panic("get_bpy_world() deprecated"); return null; }
exports.get_lights_names = function() { m_util.panic("get_lights_names() deprecated, use lights module instead"); }
exports.remove_object = function(obj) { m_util.panic("Method \"remove_object\" is deprecated"); }
exports.remove_all = function() { m_util.panic("remove_all() deprecated, use lights module instead"); }
exports.assert_type = function(value, type) { if (typeof value != type) m_util.panic("Type assertion failed: value type is not a {" + type + "}:", value); }
function process_nla_script(nla, timeline, elapsed, start_time) { if (!nla.script.length) return; if (nla.curr_script_slot >= nla.script.length) { if (nla.cyclic) { nla.curr_script_slot = 0; } else { // freeze nla.frame_offset -= cfg_ani.framerate * elapsed; return; } } var cf = calc_curr_frame(nla, timeline, start_time, false); var slot = nla.script[nla.curr_script_slot]; switch (slot.type) { case "PLAY": if (!slot.in_play) { nla.frame_offset += (slot.frame_start - cf); slot.in_play = true; reset_nla_selection(nla, slot); } else { if (cf >= slot.frame_end) { slot.in_play = false; nla.curr_script_slot++; process_nla_script(nla, timeline, elapsed, start_time); } } break; case "SELECT": case "SELECT_PLAY": if (slot.sel_state > -1) { if (slot.type == "SELECT" || (slot.type == "SELECT_PLAY" && slot.sel_state == 0)) { nla.curr_script_slot = slot.sel_state ? slot.slot_idx_hit : slot.slot_idx_miss; slot.sel_state = -1; process_nla_script(nla, timeline, elapsed, start_time); } else { if (!slot.in_play) { nla.frame_offset += (slot.frame_start - cf); slot.in_play = true; reset_nla_selection(nla, slot); } else { if (cf >= slot.frame_end) { slot.in_play = false; nla.curr_script_slot = slot.slot_idx_hit; slot.sel_state = -1; process_nla_script(nla, timeline, elapsed, start_time); } } } } else { // freeze nla.frame_offset -= cfg_ani.framerate * elapsed; } break; case "JUMP": nla.curr_script_slot = slot.slot_idx; process_nla_script(nla, timeline, elapsed, start_time); break; case "CONDJUMP": var val1 = (slot.reg1 == -1) ? slot.num1 : nla.registers[slot.reg1]; var val2 = (slot.reg2 == -1) ? slot.num2 : nla.registers[slot.reg2]; var cond_result = false; switch (slot.cond) { case "EQUAL": if (val1 == val2) cond_result = true; break; case "NOTEQUAL": if (val1 != val2) cond_result = true; break; case "LESS": if (val1 < val2) cond_result = true; break; case "GREATER": if (val1 > val2) cond_result = true; break; case "LEQUAL": if (val1 <= val2) cond_result = true; break; case "GEQUAL": if (val1 >= val2) cond_result = true; break; } if (cond_result) nla.curr_script_slot = slot.slot_idx; else nla.curr_script_slot++; process_nla_script(nla, timeline, elapsed, start_time); break; case "REGSTORE": nla.registers[slot.reg] = slot.num; nla.curr_script_slot++; process_nla_script(nla, timeline, elapsed, start_time); break; case "MATH": var val1 = (slot.reg1 == -1) ? slot.num1 : nla.registers[slot.reg1]; var val2 = (slot.reg2 == -1) ? slot.num2 : nla.registers[slot.reg2]; switch (slot.op) { case "ADD": nla.registers[slot.regd] = val1 + val2; break; case "MUL": nla.registers[slot.regd] = val1 * val2; break; case "SUB": nla.registers[slot.regd] = val1 - val2; break; case "DIV": if (val2 == 0) m_util.panic("Division by zero in NLA script"); nla.registers[slot.regd] = val1 / val2; break; } nla.curr_script_slot++; process_nla_script(nla, timeline, elapsed, start_time); break; case "NOOP": nla.curr_script_slot++; process_nla_script(nla, timeline, elapsed, start_time); break; } }
exports.check_collision = function() { m_util.panic("check_collision() deprecated, use lights module instead"); }
/** * 1 - positive pulse * -1 - negative pulse * 0 - no pulse */ function manifold_gen_pulse(manifold, logic_result) { var last_pulse = manifold.last_pulse; var pulse; var new_last_pulse; switch (manifold.type) { case exports.CT_CONTINUOUS: if (logic_result) { pulse = 1; new_last_pulse = 1; } else if (last_pulse == 1) { pulse = -1; new_last_pulse = -1; } else pulse = 0; break; case exports.CT_TRIGGER: if (logic_result && last_pulse == -1) { pulse = 1; new_last_pulse = 1; } else if (!logic_result && last_pulse == 1) { pulse = -1; new_last_pulse = -1; } else pulse = 0; break; case exports.CT_SHOT: if (logic_result && last_pulse == -1) { pulse = 1; new_last_pulse = 1; } else if (!logic_result && last_pulse == 1) { // give no ouput, but register negative pulse pulse = 0; new_last_pulse = -1; } else pulse = 0; break; case exports.CT_LEVEL: // ignore previous pulses var last_logic_result = manifold.last_logic_result; if (last_logic_result != logic_result) pulse = 1; else pulse = 0; break; default: m_util.panic("Wrong sensor manifold type: " + manifold.type); break; } if (new_last_pulse) manifold.last_pulse = new_last_pulse; return pulse; }
exports.set_dir_light_color = function(index, val) { m_util.panic("set_dir_light_color() deprecated, use lights module instead"); }
exports.add_object = function(obj) { m_util.panic("Method \"add_object\" is deprecated"); }
exports.check_ray_hit = function() { m_util.panic("check_ray_hit() deprecated, use lights module instead"); }