feat/godot: work in progress [might break]

This commit is contained in:
Leon van Kammen 2024-05-16 14:22:00 +02:00
parent 53b6527152
commit d51c7fe69a
3 changed files with 129 additions and 36 deletions

View File

@ -7,18 +7,24 @@ var player:CharacterBody3D
func _ready():
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)
#xrf.to("https://xrfragment.org/other.glb", _onXRF )
xrf.to("http://localhost:8080/example/assets/other.glb", _onXRF )
player = find_child("PlayerBody")
player.enabled = false # optional: turn off gravity
player = find_child("PlayerBody") # optional: use PlayerBody from godot-xr-tools
player.enabled = false # optional: turn off gravity
func _onXRF(event:String,data ):
if event == "scene_loaded":
scene = data
if event == 'href': # optional: hook into href events
if event == 'href':
print(data)
if event == 'src': # optional: hook into src metadata
if event == 'src':
print(data)
if event == 'teleport':
print("teleport!")
@ -56,6 +62,6 @@ func _input(event):
var intersectMesh = space_state.intersect_ray(mesh_query)
var intersectHandle = space_state.intersect_ray(handle_query)
if intersectMesh.has('collider'):
xrf.traverse( intersectMesh.collider, xrf.href_click )
xrf.traverse( intersectMesh.collider, xrf.href.click )

View File

@ -21,11 +21,13 @@ shadow_enabled = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.7, 0)
[node name="URLbar" type="RichTextLabel" parent="XROrigin3D/XRCamera3D"]
modulate = Color(0, 0, 0, 1)
offset_left = 20.0
offset_top = 20.0
offset_right = 1171.0
offset_bottom = 136.0
scale = Vector2(1.2, 1.2)
scroll_active = false
[node name="LeftHand" type="XRController3D" parent="XROrigin3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0, 0)

View File

@ -11,6 +11,8 @@ var history: Array
var animplayer: AnimationPlayer
var isModelLoading = false
var metadata
var _orphans = []
var _regex:RegEx = RegEx.new()
var callback: Callable;
var Type = {
"isColor": "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$",
@ -32,6 +34,35 @@ func _process(delta):
# 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:
var URI = {"string":url, "next": null}
@ -46,8 +77,9 @@ func parseURL(url: String) -> Dictionary:
# Split URL by '/' to separate domain, path, and file
parts = url.split("/")
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)
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)
else:
URI["path"] = path_and_file
else:
if !URI.has("path"):
URI["path"] = self.URI.path # copy from current URI
if !URI.has("domain"):
URI["domain"] = self.URI.domain
# Check if there's a query string
@ -120,7 +154,7 @@ func guess_type(str: String) -> Dictionary:
return v
####################################################################################################
# Model Related functions
# Navigation Related functions
####################################################################################################
func back():
@ -143,19 +177,31 @@ func to(url, f:Callable ):
URI.isLocal = true
if !URI.isLocal:
var http_request = HTTPRequest.new()
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.")
fetchURL(url, downloadModelSuccess )
if self.URI:
self.URI.next = null
self.history.push_back(self.URI )
self.URI = URI
if URI.isLocal && URI.fragment.has('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):
# TODO: here different parsing functions should be called
@ -167,9 +213,10 @@ func downloadModelSuccess(result, response_code, headers, body):
_parseXRFMetadata(scene)
traverse( scene, _parseXRFMetadata )
# setup actions & embeds
traverse( scene, href_init )
traverse( scene, src_init )
traverse( scene, href.init )
traverse( scene, src.init )
setPredefinedSceneView()
cleanup()
callback.call("scene_loaded", scene)
func loadModelFromBufferByGLTFDocument(body):
@ -296,23 +343,61 @@ func href_init(node:Node):
col3D.make_convex_from_siblings() # generate collision from MeshInstance3D siblings
parent.add_child(area3D)
func href_click(node:Node):
if node.has_meta("XRF"):
var XRF = node.get_meta("XRF")
if XRF.has('href'):
to(XRF.href.string,callback)
callback.call("href", node)
var href = {
"click": func init(node:Node):
if node.has_meta("XRF"):
var XRF = node.get_meta("XRF")
if XRF.has('href'):
print("TELEPORT")
to(XRF.href.string,callback)
callback.call("href", 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)
}
func src_init(node:Node):
if node.has_meta("XRF"):
var XRF = node.get_meta("XRF")
if XRF.has('src'):
var mesh = node as MeshInstance3D
if mesh != null:
var mat = mesh.get_active_material(0) as BaseMaterial3D
mat = mat.duplicate()
mat.transparency = mat.TRANSPARENCY_ALPHA
mat.albedo = Color(1.0,1.0,1.0, 0.3) # 0.5 sets 50% opacity
mesh.set_surface_override_material(0,mat)
callback.call("src", {"node":node,"XRF":XRF} )
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"):
var XRF = node.get_meta("XRF")
if XRF.has('src'):
var mesh = node as MeshInstance3D
if mesh != null:
var mat = mesh.get_active_material(0) as BaseMaterial3D
mat = mat.duplicate()
mat.transparency = mat.TRANSPARENCY_ALPHA
mat.albedo = Color(1.0,1.0,1.0, 0.3) # 0.5 sets 50% opacity
mesh.set_surface_override_material(0,mat)
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)
}