feat/godot: work in progress [might break]
This commit is contained in:
parent
53b6527152
commit
d51c7fe69a
3 changed files with 129 additions and 36 deletions
|
|
@ -7,18 +7,24 @@ var player:CharacterBody3D
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
xrf = preload("res://xrfragment.gd").new()
|
xrf = preload("res://xrfragment.gd").new()
|
||||||
|
print( xrf.parseURL2("https://foo.com/abc.gltf#foo=2") )
|
||||||
|
return
|
||||||
|
|
||||||
|
xrf.src.addExtension.call("wav", xrf.src.audio ) # extensible support for
|
||||||
|
xrf.src.addExtension.call("ogg", xrf.src.audio ) # src-metadata (a la carte)
|
||||||
add_child(xrf)
|
add_child(xrf)
|
||||||
#xrf.to("https://xrfragment.org/other.glb", _onXRF )
|
#xrf.to("https://xrfragment.org/other.glb", _onXRF )
|
||||||
xrf.to("http://localhost:8080/example/assets/other.glb", _onXRF )
|
xrf.to("http://localhost:8080/example/assets/other.glb", _onXRF )
|
||||||
player = find_child("PlayerBody")
|
player = find_child("PlayerBody") # optional: use PlayerBody from godot-xr-tools
|
||||||
player.enabled = false # optional: turn off gravity
|
player.enabled = false # optional: turn off gravity
|
||||||
|
|
||||||
|
|
||||||
func _onXRF(event:String,data ):
|
func _onXRF(event:String,data ):
|
||||||
if event == "scene_loaded":
|
if event == "scene_loaded":
|
||||||
scene = data
|
scene = data
|
||||||
if event == 'href': # optional: hook into href events
|
if event == 'href':
|
||||||
print(data)
|
print(data)
|
||||||
if event == 'src': # optional: hook into src metadata
|
if event == 'src':
|
||||||
print(data)
|
print(data)
|
||||||
if event == 'teleport':
|
if event == 'teleport':
|
||||||
print("teleport!")
|
print("teleport!")
|
||||||
|
|
@ -56,6 +62,6 @@ func _input(event):
|
||||||
var intersectMesh = space_state.intersect_ray(mesh_query)
|
var intersectMesh = space_state.intersect_ray(mesh_query)
|
||||||
var intersectHandle = space_state.intersect_ray(handle_query)
|
var intersectHandle = space_state.intersect_ray(handle_query)
|
||||||
if intersectMesh.has('collider'):
|
if intersectMesh.has('collider'):
|
||||||
xrf.traverse( intersectMesh.collider, xrf.href_click )
|
xrf.traverse( intersectMesh.collider, xrf.href.click )
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,13 @@ shadow_enabled = true
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.7, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.7, 0)
|
||||||
|
|
||||||
[node name="URLbar" type="RichTextLabel" parent="XROrigin3D/XRCamera3D"]
|
[node name="URLbar" type="RichTextLabel" parent="XROrigin3D/XRCamera3D"]
|
||||||
|
modulate = Color(0, 0, 0, 1)
|
||||||
offset_left = 20.0
|
offset_left = 20.0
|
||||||
offset_top = 20.0
|
offset_top = 20.0
|
||||||
offset_right = 1171.0
|
offset_right = 1171.0
|
||||||
offset_bottom = 136.0
|
offset_bottom = 136.0
|
||||||
scale = Vector2(1.2, 1.2)
|
scale = Vector2(1.2, 1.2)
|
||||||
|
scroll_active = false
|
||||||
|
|
||||||
[node name="LeftHand" type="XRController3D" parent="XROrigin3D"]
|
[node name="LeftHand" type="XRController3D" parent="XROrigin3D"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0, 0)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ var history: Array
|
||||||
var animplayer: AnimationPlayer
|
var animplayer: AnimationPlayer
|
||||||
var isModelLoading = false
|
var isModelLoading = false
|
||||||
var metadata
|
var metadata
|
||||||
|
var _orphans = []
|
||||||
|
var _regex:RegEx = RegEx.new()
|
||||||
var callback: Callable;
|
var callback: Callable;
|
||||||
var Type = {
|
var Type = {
|
||||||
"isColor": "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$",
|
"isColor": "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$",
|
||||||
|
|
@ -32,6 +34,35 @@ func _process(delta):
|
||||||
# URI Related functions
|
# URI Related functions
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
|
func parseURL2(url: String) -> Dictionary:
|
||||||
|
var regex:RegEx = RegEx.new()
|
||||||
|
regex.compile("\\S+") # Negated whitespace character class.
|
||||||
|
var results = []
|
||||||
|
for result in regex.search_all(url.replace("/"," ")):
|
||||||
|
results.push_back(result.get_string())
|
||||||
|
print(results)
|
||||||
|
|
||||||
|
return {} # Return empty dictionary if URL doesn't match
|
||||||
|
|
||||||
|
var groups = regex.get_group_list(url)
|
||||||
|
var parsed_url = {
|
||||||
|
"source": url,
|
||||||
|
"scheme": groups[1] ||"", # Use nullish coalescing for optional scheme
|
||||||
|
"authority": groups[2] ||"",
|
||||||
|
"userInfo": (groups[4]||"") + ":" + (groups[5]||""), # Combine user and password
|
||||||
|
"user": groups[4] ||"",
|
||||||
|
"password": groups[5] ||"",
|
||||||
|
"host": groups[6] ||"",
|
||||||
|
"port": groups[7] || "", # Convert port to int or default to 0
|
||||||
|
"relative": groups[8] ||"",
|
||||||
|
"path": groups[9] ||"",
|
||||||
|
"directory": (groups[9]||"").split("/")[0] || "", # Extract directory path
|
||||||
|
"file": groups[9].split("/")[-1] ||"", # Extract filename
|
||||||
|
"query": groups[10] ||"",
|
||||||
|
"fragment": groups[11] ||"",
|
||||||
|
}
|
||||||
|
return parsed_url
|
||||||
|
|
||||||
func parseURL(url: String) -> Dictionary:
|
func parseURL(url: String) -> Dictionary:
|
||||||
var URI = {"string":url, "next": null}
|
var URI = {"string":url, "next": null}
|
||||||
|
|
||||||
|
|
@ -46,8 +77,9 @@ func parseURL(url: String) -> Dictionary:
|
||||||
# Split URL by '/' to separate domain, path, and file
|
# Split URL by '/' to separate domain, path, and file
|
||||||
parts = url.split("/")
|
parts = url.split("/")
|
||||||
URI["domain"] = parts[0]
|
URI["domain"] = parts[0]
|
||||||
if parts.size() > 1:
|
|
||||||
parts.remove_at(0)
|
parts.remove_at(0)
|
||||||
|
|
||||||
|
if parts.size() > 0:
|
||||||
var path_and_file = "/".join(parts)
|
var path_and_file = "/".join(parts)
|
||||||
path_and_file = path_and_file.split("?")[0]
|
path_and_file = path_and_file.split("?")[0]
|
||||||
path_and_file = path_and_file.split("#")[0]
|
path_and_file = path_and_file.split("#")[0]
|
||||||
|
|
@ -56,8 +88,10 @@ func parseURL(url: String) -> Dictionary:
|
||||||
URI["path"] = "/".join(path_and_file_parts)
|
URI["path"] = "/".join(path_and_file_parts)
|
||||||
else:
|
else:
|
||||||
URI["path"] = path_and_file
|
URI["path"] = path_and_file
|
||||||
else:
|
|
||||||
|
if !URI.has("path"):
|
||||||
URI["path"] = self.URI.path # copy from current URI
|
URI["path"] = self.URI.path # copy from current URI
|
||||||
|
if !URI.has("domain"):
|
||||||
URI["domain"] = self.URI.domain
|
URI["domain"] = self.URI.domain
|
||||||
|
|
||||||
# Check if there's a query string
|
# Check if there's a query string
|
||||||
|
|
@ -120,7 +154,7 @@ func guess_type(str: String) -> Dictionary:
|
||||||
return v
|
return v
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# Model Related functions
|
# Navigation Related functions
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
func back():
|
func back():
|
||||||
|
|
@ -143,12 +177,7 @@ func to(url, f:Callable ):
|
||||||
URI.isLocal = true
|
URI.isLocal = true
|
||||||
|
|
||||||
if !URI.isLocal:
|
if !URI.isLocal:
|
||||||
var http_request = HTTPRequest.new()
|
fetchURL(url, downloadModelSuccess )
|
||||||
add_child(http_request)
|
|
||||||
http_request.request_completed.connect(downloadModelSuccess)
|
|
||||||
var error = http_request.request(url)
|
|
||||||
if error != OK:
|
|
||||||
push_error("An error occurred in the HTTP request.")
|
|
||||||
if self.URI:
|
if self.URI:
|
||||||
self.URI.next = null
|
self.URI.next = null
|
||||||
self.history.push_back(self.URI )
|
self.history.push_back(self.URI )
|
||||||
|
|
@ -156,6 +185,23 @@ func to(url, f:Callable ):
|
||||||
if URI.isLocal && URI.fragment.has('pos'):
|
if URI.isLocal && URI.fragment.has('pos'):
|
||||||
callback.call("teleport", self.posToTransform3D( URI.fragment.pos ) )
|
callback.call("teleport", self.posToTransform3D( URI.fragment.pos ) )
|
||||||
|
|
||||||
|
####################################################################################################
|
||||||
|
# Model Related functions
|
||||||
|
####################################################################################################
|
||||||
|
|
||||||
|
func fetchURL(url:String, f:Callable) -> HTTPRequest:
|
||||||
|
var http_request = HTTPRequest.new()
|
||||||
|
_orphans.push_back(http_request)
|
||||||
|
add_child(http_request)
|
||||||
|
http_request.request_completed.connect(downloadModelSuccess)
|
||||||
|
var error = http_request.request(url)
|
||||||
|
if error != OK:
|
||||||
|
push_error("An error occurred in the HTTP request.")
|
||||||
|
return http_request
|
||||||
|
|
||||||
|
func cleanup():
|
||||||
|
for orphan in _orphans:
|
||||||
|
remove_child(orphan)
|
||||||
|
|
||||||
func downloadModelSuccess(result, response_code, headers, body):
|
func downloadModelSuccess(result, response_code, headers, body):
|
||||||
# TODO: here different parsing functions should be called
|
# TODO: here different parsing functions should be called
|
||||||
|
|
@ -167,9 +213,10 @@ func downloadModelSuccess(result, response_code, headers, body):
|
||||||
_parseXRFMetadata(scene)
|
_parseXRFMetadata(scene)
|
||||||
traverse( scene, _parseXRFMetadata )
|
traverse( scene, _parseXRFMetadata )
|
||||||
# setup actions & embeds
|
# setup actions & embeds
|
||||||
traverse( scene, href_init )
|
traverse( scene, href.init )
|
||||||
traverse( scene, src_init )
|
traverse( scene, src.init )
|
||||||
setPredefinedSceneView()
|
setPredefinedSceneView()
|
||||||
|
cleanup()
|
||||||
callback.call("scene_loaded", scene)
|
callback.call("scene_loaded", scene)
|
||||||
|
|
||||||
func loadModelFromBufferByGLTFDocument(body):
|
func loadModelFromBufferByGLTFDocument(body):
|
||||||
|
|
@ -296,14 +343,38 @@ func href_init(node:Node):
|
||||||
col3D.make_convex_from_siblings() # generate collision from MeshInstance3D siblings
|
col3D.make_convex_from_siblings() # generate collision from MeshInstance3D siblings
|
||||||
parent.add_child(area3D)
|
parent.add_child(area3D)
|
||||||
|
|
||||||
func href_click(node:Node):
|
var href = {
|
||||||
|
"click": func init(node:Node):
|
||||||
if node.has_meta("XRF"):
|
if node.has_meta("XRF"):
|
||||||
var XRF = node.get_meta("XRF")
|
var XRF = node.get_meta("XRF")
|
||||||
if XRF.has('href'):
|
if XRF.has('href'):
|
||||||
|
print("TELEPORT")
|
||||||
to(XRF.href.string,callback)
|
to(XRF.href.string,callback)
|
||||||
callback.call("href", node)
|
callback.call("href", node),
|
||||||
|
|
||||||
func src_init(node:Node):
|
"init": func href_init(node:Node):
|
||||||
|
if node.has_meta("XRF"):
|
||||||
|
var XRF = node.get_meta("XRF")
|
||||||
|
if XRF.has('href'):
|
||||||
|
var parent = node.get_parent()
|
||||||
|
var area3D = Area3D.new()
|
||||||
|
var col3D = CollisionShape3D.new()
|
||||||
|
var group = MeshInstance3D.new()
|
||||||
|
parent.remove_child(node)
|
||||||
|
area3D.add_child(node)
|
||||||
|
area3D.add_child(col3D)
|
||||||
|
col3D.make_convex_from_siblings() # generate collision from MeshInstance3D siblings
|
||||||
|
parent.add_child(area3D)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var src = {
|
||||||
|
"extension":{},
|
||||||
|
|
||||||
|
"addExtension": func addExtension( extension:String, f:Callable): # flexible way for adding extension handlers
|
||||||
|
src.extension[ extension ] = f,
|
||||||
|
|
||||||
|
"init": func init(node:Node):
|
||||||
if node.has_meta("XRF"):
|
if node.has_meta("XRF"):
|
||||||
var XRF = node.get_meta("XRF")
|
var XRF = node.get_meta("XRF")
|
||||||
if XRF.has('src'):
|
if XRF.has('src'):
|
||||||
|
|
@ -314,5 +385,19 @@ func src_init(node:Node):
|
||||||
mat.transparency = mat.TRANSPARENCY_ALPHA
|
mat.transparency = mat.TRANSPARENCY_ALPHA
|
||||||
mat.albedo = Color(1.0,1.0,1.0, 0.3) # 0.5 sets 50% opacity
|
mat.albedo = Color(1.0,1.0,1.0, 0.3) # 0.5 sets 50% opacity
|
||||||
mesh.set_surface_override_material(0,mat)
|
mesh.set_surface_override_material(0,mat)
|
||||||
callback.call("src", {"node":node,"XRF":XRF} )
|
for ext in src.extension:
|
||||||
|
_regex.compile("^.*."+ext+"$")
|
||||||
|
if _regex.search(XRF.src.path):
|
||||||
|
var url:String = XRF.src.protocol+"://"+XRF.src.domain+"/"+XRF.src.path
|
||||||
|
print("src: fetching "+url)
|
||||||
|
print(XRF.src)
|
||||||
|
fetchURL(url, src.extension[ext] )
|
||||||
|
callback.call("src", {"node":node,"XRF":XRF} ),
|
||||||
|
|
||||||
|
# some builtin handlers
|
||||||
|
"audio": func audio(node:Node, extension:String):
|
||||||
|
return func onFile(result, response_code, headers, body):
|
||||||
|
var src = node.XRF.src
|
||||||
|
print(src.string+" audioooo "+extension+" "+response_code)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue