Created
October 4, 2018 04:59
-
-
Save 1ec5/48bd71eba1b2d2addbac3cfdbc3372e1 to your computer and use it in GitHub Desktop.
aer2x3dom
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function anchorOnMouseOver(evt) { | |
var div = document.getElementsByClassName("x3dom-canvasdiv")[0]; | |
div.style.cursor = "pointer"; | |
alert("in"); | |
} | |
function anchorOnMouseOut(evt) { | |
var div = document.getElementsByClassName("x3dom-canvasdiv")[0]; | |
div.style.cursor = "move"; | |
alert("out"); | |
} | |
function attachAnchorOnClick(evt) { | |
var x3d = document.getElementsByTagName("x3d")[0]; | |
var anchors = x3d.getElementsByTagName("anchor"); | |
for (var anchor in anchors) { | |
anchor.addEventListener("mouseover", anchorOnMouseOver, false); | |
anchor.addEventListener("mouseout", anchorOnMouseOut, false); | |
} | |
} | |
document.addEventListener("load", attachAnchorOnClick, false); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys, random | |
from os import path | |
from xml.dom.minidom import Document, Element, Attr | |
X3DOM_CSS = "./x3dom-v1.0.css" | |
X3DOM_JS = "./x3dom-v1.0.js" | |
CUSTOM_JS = "./aer2x3dom.js" | |
X3D_NS = "http://www.web3d.org/specifications/x3d-namespace" | |
XHTML_NS = "http://www.w3.org/1999/xhtml" | |
ANCHOR_TEXTURE_ADDED = False | |
CONNECTORS = {} | |
def dom_for_aer_array(aer_array, item_type=str): | |
aer_array = aer_array.split(",") | |
assert int(aer_array[0]) == len(aer_array) - 1 | |
aer_array[1:] = [str(item_type(item)) for item in aer_array[1:]] | |
return aer_array[1:] | |
def dom_str_for_aer_array(aer_array, item_type=None): | |
return " ".join(dom_for_aer_array(aer_array, item_type)) | |
def abs_url(base_url, rel_url): | |
return base_url + "/" + rel_url if base_url else rel_url | |
def dom_for_aer_line(doc, aer_line): | |
global CONNECTORS | |
root = doc.getElementsByTagName("x3d")[0] | |
orig_url = root.getAttribute("altSrc") | |
if orig_url: | |
orig_url = path.split(orig_url)[0] + "/" | |
aer_line = aer_line.split(":") | |
aer_type = aer_line[0][:4] | |
aer_id = aer_line[0][4:] | |
# Parse the line. | |
aer_data = {} | |
for pair in aer_line[1:]: | |
pair = pair.split("=", 1) | |
aer_data[pair[0]] = pair[1] if len(pair) > 1 else None | |
# Special element types. | |
if aer_type == "HEAD": | |
if aer_data.get("DFmt") != "A": | |
print >> sys.stderr, "Binary Atmosphere model files not supported." | |
sys.exit(1) | |
return None | |
elif aer_type == "NEN3" and aer_data.get("name") == "Viewer": | |
root.setAttribute("altImg", aer_data["icon"]) | |
return None | |
elif aer_type == "WRLD": | |
root.setAttribute("id", aer_data.get("wlnm")) | |
root.setAttribute("title", aer_data.get("irtc")) | |
url = aer_data.get("iref") | |
if url: | |
root.setAttribute("altSrc", url.replace("|", ":")) | |
return None | |
# Resource element types. | |
if aer_type == "ACTR": | |
viewport = doc.createElement("viewport") | |
# TODO: viewport.position | |
# viewport.setAttribute("position", | |
# dom_str_for_aer_array(aer_data.get("lkdr"), float)) | |
# viewport.setAttribute("orientation", | |
# dom_str_for_aer_array(aer_data.get("oRnt"), float)) | |
return viewport | |
elif aer_type == "CON3": | |
if "vals" in aer_data and aer_id not in CONNECTORS: | |
CONNECTORS[aer_id] = tuple(dom_for_aer_array(aer_data["vals"], | |
float)) | |
return None | |
elif aer_type == "STCL": | |
appearance = doc.createElement("appearance") | |
appearance.setAttribute("def", "%s%s" % (aer_type, aer_id)) | |
material = doc.createElement("material") | |
material.appendChild(doc.createTextNode("")) | |
r = float(aer_data.get("sred", 0)) | |
g = float(aer_data.get("sgrn", 0)) | |
b = float(aer_data.get("sblu", 0)) | |
material.setAttribute("diffuseColor", "%f %f %f" % (r, g, b)) | |
appearance.appendChild(material) | |
return appearance | |
elif aer_type == "TXTR": | |
appearance = doc.createElement("appearance") | |
appearance.setAttribute("def", "%s%s" % (aer_type, aer_id)) | |
material = doc.createElement("imagetexture") | |
material.appendChild(doc.createTextNode("")) | |
material.setAttribute("url", abs_url(orig_url, aer_data.get("urln"))) | |
appearance.appendChild(material) | |
return appearance | |
transform = doc.createElement("transform") | |
transform.setAttribute("translation", "0 0 0") # debug | |
# Set common attributes. | |
shape = doc.createElement("shape") | |
# shape.setAttribute("DEF", "%s%s" % (aer_type, aer_id)) | |
start_pt = None | |
if "obnm" in aer_data: | |
shape.setAttribute("id", aer_data["obnm"]) | |
if "cn3s" in aer_data: | |
connector_idxs = dom_for_aer_array(aer_data["cn3s"]) | |
connectors = [CONNECTORS[idx] for idx in connector_idxs | |
if idx in CONNECTORS] | |
if len(connectors): | |
start_pt = [float(i) for i in connectors[0]] | |
transform.setAttribute("translation", "%f %f %f" % tuple(start_pt)) | |
transform.appendChild(shape) | |
appearance_id = None | |
# Determine the model element type. | |
if aer_type == "BOX3": | |
box = doc.createElement("box") | |
box.appendChild(doc.createTextNode("")) | |
box.setAttribute("solid", "true") | |
shape.appendChild(box) | |
if len(connectors) > 1: | |
end_pt = [float(i) for i in connectors[1]] | |
scale = [(e - s) / 2 for s, e in zip(start_pt, end_pt)] | |
transform.setAttribute("scale", "%f %f %f" % tuple(scale)) | |
elif aer_type == "COL3": | |
cylinder = doc.createElement("cylinder") | |
cylinder.appendChild(doc.createTextNode("")) | |
cylinder.setAttribute("radius", str(float(aer_data.get("widt")))) | |
shape.appendChild(cylinder) | |
cylinder.setAttribute("solid", "false") | |
if len(connectors) > 1: | |
end_pt = [float(i) for i in connectors[1]] | |
# TODO: transform.rotation for cylinders | |
height = end_pt[1] - start_pt[1] | |
transform.setAttribute("scale", "0 %f 0" % height) | |
elif aer_type == "FLR3": | |
box = doc.createElement("box") | |
box.appendChild(doc.createTextNode("")) | |
box.setAttribute("solid", "true") | |
transform.setAttribute("scale", "1 1 %f" % float(aer_data.get("thik", 1))) # debug | |
shape.appendChild(box) | |
start_pt[2] += float(aer_data.get("plny", 0)) | |
transform.setAttribute("translation", "0 %f 0" % tuple(start_pt)) | |
elif aer_type == "PORT": | |
anchor = doc.createElement("anchor") | |
anchor.setAttribute("url", abs_url(orig_url, aer_data.get("wrul"))) | |
transform.appendChild(anchor) | |
sphere = doc.createElement("sphere") | |
sphere.appendChild(doc.createTextNode("")) | |
sphere.setAttribute("solid", "true") | |
shape.appendChild(sphere) | |
transform.removeChild(shape) | |
anchor.appendChild(shape) | |
start_pt = start_pt or [0, 1.5, 0] # debug | |
transform.setAttribute("translation", "%f %f %f" % tuple(start_pt)) | |
global ANCHOR_TEXTURE_ADDED | |
appearance_id = "_anchor_texture" | |
if not ANCHOR_TEXTURE_ADDED: | |
appearance = doc.createElement("appearance") | |
appearance.setAttribute("id", "_anchor_texture") | |
appearance.setAttribute("def", "_anchor_texture") | |
material = doc.createElement("material") | |
material.appendChild(doc.createTextNode("")) | |
material.setAttribute("emissiveColor", "0 0 1") | |
material.setAttribute("transparency", "0.4") | |
appearance.appendChild(material) | |
collision = doc.getElementsByTagName("collision")[0] | |
collision.appendChild(appearance) | |
ANCHOR_TEXTURE_ADDED = True | |
else: | |
return doc.createComment("Unsupported element type %s" % aer_type) | |
# TODO: shape.appearance | |
if len(doc.getElementsByTagName("appearance")): | |
appearance = doc.createElement("appearance") | |
appearance.appendChild(doc.createTextNode("")) | |
if not appearance_id: | |
appearance_idx = random.randint(0, len(doc.getElementsByTagName("appearance")) - 1) # debug | |
appearance_id = doc.getElementsByTagName("appearance")[appearance_idx].getAttribute("def") | |
appearance.setAttribute("use", appearance_id) | |
shape.appendChild(appearance) | |
# return shape | |
return transform | |
def html_with_model(x3d_doc): | |
x3d_root = x3d_doc.getElementsByTagName("x3d")[0] | |
doc = Document() | |
root = doc.createElement("html") | |
root.namespaceURI = XHTML_NS | |
root.setAttribute("xmlns", root.namespaceURI) | |
doc.appendChild(root) | |
orig_url = x3d_root.getAttribute("altSrc") | |
if orig_url: | |
root.setAttributeNS("xml", "xml:base", path.split(orig_url)[0] + "/") | |
head = doc.createElement("head") | |
root.appendChild(head) | |
title = doc.createElement("title") | |
model_title = x3d_root.getAttribute("title") | |
title.appendChild(doc.createTextNode(model_title)) | |
head.appendChild(title) | |
meta_generator = doc.createElement("meta") | |
meta_generator.setAttribute("name", "generator") | |
meta_generator.setAttribute("content", "aer2x3dom") | |
head.appendChild(meta_generator) | |
link_icon = doc.createElement("link") | |
link_icon.setAttribute("rel", "icon") | |
link_icon.setAttribute("href", x3d_root.getAttribute("altImg")) | |
link_icon.setAttribute("type", "image/png") | |
head.appendChild(link_icon) | |
link_css = doc.createElement("link") | |
link_css.setAttribute("rel", "stylesheet") | |
link_css.setAttribute("type", "text/css") | |
link_css.setAttribute("media", "screen") | |
link_css.setAttribute("href", X3DOM_CSS) | |
head.appendChild(link_css) | |
script = doc.createElement("script") | |
script.setAttribute("type", "text/javascript") | |
script.setAttribute("src", CUSTOM_JS) | |
script.appendChild(doc.createTextNode("")) | |
head.appendChild(script) | |
body = doc.createElement("body") | |
root.appendChild(body) | |
h1 = doc.createElement("h1") | |
h1.appendChild(doc.createTextNode(model_title)) | |
body.appendChild(h1) | |
x3d_root.setAttribute("width", "600px") | |
x3d_root.setAttribute("height", "400px") | |
body.appendChild(x3d_root) | |
p_source = doc.createElement("p") | |
p_source.appendChild(doc.createTextNode("Source:")) | |
a_source = doc.createElement("a") | |
a_source.setAttribute("href", orig_url) | |
a_source.appendChild(doc.createTextNode("Adobe Atmosphere format")) | |
p_source.appendChild(a_source) | |
body.appendChild(p_source) | |
script = doc.createElement("script") | |
script.setAttribute("type", "text/javascript") | |
script.setAttribute("src", X3DOM_JS) | |
script.appendChild(doc.createTextNode("")) | |
body.appendChild(script) | |
return doc | |
def main(): | |
aer_path = None | |
html = False | |
for arg in sys.argv[1:]: | |
if arg in ["--html", "-xhtml"]: | |
html = True | |
else: | |
aer_path = arg | |
if not aer_path: | |
print >> sys.stderr, "No Atmosphere model file specified." | |
sys.exit(1) | |
doc = Document() | |
root = doc.createElement("x3d") | |
root.namespaceURI = X3D_NS | |
root.setAttribute("xmlns", root.namespaceURI) | |
doc.appendChild(root) | |
scene = doc.createElement("scene") | |
root.appendChild(scene) | |
collision = doc.createElement("collision") | |
scene.appendChild(collision) | |
background = doc.createElement("background") | |
background.appendChild(doc.createTextNode("")) | |
background.setAttribute("groundColor", "0.2 0.2 0.2") | |
background.setAttribute("skyColor", "0.8 0.8 0.98") | |
collision.appendChild(background) | |
with open(aer_path, "r") as aer_file: | |
for aer_line in aer_file: | |
elt = dom_for_aer_line(doc, aer_line) | |
if not elt: | |
continue | |
collision.appendChild(elt) | |
xml_path = path.splitext(aer_path)[0] | |
xml_path += ".html" if html else ".x3d" | |
with open(xml_path, "w") as xml_file: | |
if not html: | |
print >> xml_file, doc.toprettyxml() | |
return | |
html_doc = html_with_model(doc) | |
if html_doc: | |
print >> xml_file, html_doc.toprettyxml() | |
if __name__ == "__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys, gzip, re, struct | |
from os import path | |
# Arrays: key + array size (little-endian?) + NULL + contents | |
# Strings: key + string length??? + NULL + contents + NULL | |
URLS = set() | |
def scan_line(num, buf): | |
bool_keys = ["aplt", "cnpr", "ilbo", "isab", "isbo", "lite", "loop", "rlbo", | |
"rldl", "rlll", "rlsu", "rsbo", "scty", "strt", "subt"] | |
int_keys = ["aple", "avcl", "dpth", "face", "facs", "ivis", "lock", "nwst", | |
"texr"] | |
dbl_keys = ["bl..", "btwi", "ca..", "da..", "db..", "de..", "dsbr", "embr", | |
"gr..", "hite", "lmss", "mm..", "mn..", "offu", "offv", "plny", | |
"rd..", "rota", "sb..", "sfbr", "sgrn", "sizu", "sizv", "sblu", | |
"so..", "sred", "su..", "sv..", "thik", "tpwi", "widt", "wrpv", | |
"wrpu"] | |
url_keys = ["icon", "irur", "jvsr", "urln", "wrul"] | |
ints_keys = ["cn3s", "list", "lmls", "stl2"] | |
dbls_keys = ["lkdr", "oRNt", "oRnt", "size", "vals"] | |
types_keys = ["idnt", "stid"] | |
#print head.group(1) | |
data = {} | |
while buf: | |
# Unpack a key. | |
try: | |
key = struct.unpack_from("<4s", buf)[0] | |
except struct.error as err: | |
print ">>> Warning: Object %i truncated." % num | |
break | |
buf = buf[struct.calcsize("<4s"):] | |
if not re.match(r"[\w.*]+", key): | |
print ">>> Error: %s is not a valid key. Object %i is corrupted." % (repr(key), num) | |
break | |
# Unpack its size. | |
try: | |
val_len = int(struct.unpack_from("<H", buf)[0]) | |
except struct.error as err: | |
print ">>> Warning: Object %i truncated." % num | |
break | |
buf = buf[struct.calcsize("<H"):] | |
# Determine the format string for the value. | |
if key in dbl_keys and val_len == 8: | |
fmt = "<d" | |
elif (key in int_keys or key in dbl_keys or key in bool_keys) and \ | |
val_len == 4: | |
fmt = "<i" | |
elif key in ints_keys: | |
fmt = "<%ii" % (val_len / 4) | |
elif key in dbls_keys: | |
fmt = "<%id" % (val_len / 8) | |
else: | |
fmt = "<%is" % val_len | |
#val = struct.unpack_from(fmt, buf)[0] | |
# Unpack the value. | |
try: | |
val = struct.unpack_from(fmt, buf) | |
if key not in ints_keys and key not in dbls_keys: | |
val = val[0] | |
except struct.error as err: | |
print ">>> Error: Object %i is corrupted." % num | |
print ">>> \tKeys so far:", data.keys() | |
break | |
buf = buf[struct.calcsize(fmt):] | |
# Format the value. | |
if type(val) is str and val and val[-1] == "\x00": | |
val = val[:-1] | |
if key in bool_keys: | |
val = bool(val) | |
#elif key in int_keys: | |
# try: | |
# val = int(ord(val or "\x00")) | |
# except TypeError as err: | |
# print ">>> Warning: Non-integer %s set for field %s." % (repr(val), key) | |
elif key in url_keys: | |
URLS.add(val) | |
elif key in types_keys: | |
def s_type(scanner, token): return token | |
scanner = re.Scanner([(r"[A-Z0-9]{4}", s_type)]) | |
val = tuple(scanner.scan(val)[0]) | |
# Add the value to the dataset. | |
#print "\t", key, val | |
data[key] = val | |
#print "--" | |
return data | |
def main(): | |
aer_name = sys.argv[1] | |
if not aer_name.endswith(".aer"): | |
return | |
parse = len(sys.argv) > 2 and sys.argv[2] | |
wld_name = path.splitext(path.basename(aer_name))[0] | |
header = "" | |
with open(aer_name, "r") as aer_f: | |
header = aer_f.readline() | |
with open(aer_name, "rb") as aer_f: | |
aer = aer_f.read() | |
with open(wld_name + ".dat.gz", "wb") as dat_f: | |
dat_f.write(aer[len(header):]) | |
dat_f = gzip.GzipFile(wld_name + ".dat.gz", "rb") | |
dat = dat_f.read() | |
dat_f.close() | |
with open(wld_name + ".dat", "wb") as dst_f: | |
dst_f.write(dat) | |
for num, line in enumerate(re.split(r"\n(?=[A-Z0-9]{4}\d)", dat)): | |
head = re.match(r"^([A-Z0-9]{4})(\d+):", line) | |
if not head: | |
print "--" | |
continue | |
data = line[len(head.group(1) + head.group(2)) + 1:].strip() | |
if parse: | |
data = scan_line(num, data) | |
print str(num).zfill(4), head.group(1), head.group(2).zfill(3), data | |
else: | |
print str(num).zfill(4), head.group(1), head.group(2).zfill(3), repr(data[:70]) | |
print "----" | |
URLS.add("./Viewer.png") | |
URLS.add("./%s.ctl" % wld_name) | |
for url in URLS: | |
print url | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment