File size: 5,407 Bytes
f475b68
 
 
 
 
 
 
 
 
 
 
 
 
2ffb026
f475b68
2ffb026
f475b68
2ffb026
 
 
f475b68
 
 
 
 
2ffb026
f475b68
2ffb026
f475b68
2ffb026
f475b68
2ffb026
f475b68
 
2ffb026
 
 
 
 
 
 
 
f475b68
 
 
 
 
 
 
2ffb026
f475b68
2ffb026
f475b68
2ffb026
f475b68
2ffb026
f475b68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ffb026
f475b68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import streamlit as st
import os
import base64
from pathlib import Path
import shutil

def load_aframe_and_extras():
    return """
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/aframe-event-set-component.min.js"></script>
    <script>
    AFRAME.registerComponent('draggable', {
      init: function () {
        this.el.setAttribute('class', 'raycastable');
        this.el.setAttribute('cursor-listener', '');
        this.dragHandler = this.dragMove.bind(this);
        this.el.sceneEl.addEventListener('mousemove', this.dragHandler);
        this.el.addEventListener('mousedown', this.onDragStart.bind(this));
        this.el.addEventListener('mouseup', this.onDragEnd.bind(this));
        this.camera = document.querySelector('[camera]');
      },
      remove: function () {
        this.el.removeAttribute('cursor-listener');
        this.el.sceneEl.removeEventListener('mousemove', this.dragHandler);
      },
      onDragStart: function (evt) {
        this.isDragging = true;
        this.el.emit('dragstart');
      },
      onDragEnd: function (evt) {
        this.isDragging = false;
        this.el.emit('dragend');
      },
      dragMove: function (evt) {
        if (!this.isDragging) return;
        var camera = this.camera;
        var vector = new THREE.Vector3(evt.clientX / window.innerWidth * 2 - 1, -(evt.clientY / window.innerHeight) * 2 + 1, 0.5);
        vector.unproject(camera);
        var dir = vector.sub(camera.position).normalize();
        var distance = -camera.position.y / dir.y;
        var pos = camera.position.clone().add(dir.multiplyScalar(distance));
        this.el.setAttribute('position', pos);
      }
    });
    </script>
    """

def create_aframe_entity(file_path, file_type, position):
    if file_type == 'obj':
        return f'<a-entity position="{position}" obj-model="obj: #{Path(file_path).stem}" class="raycastable" draggable></a-entity>'
    elif file_type == 'glb':
        return f'<a-entity position="{position}" gltf-model="#{Path(file_path).stem}" class="raycastable" draggable></a-entity>'
    elif file_type in ['webp', 'png']:
        return f'<a-image position="{position}" src="#{Path(file_path).stem}" width="1" height="1" class="raycastable" draggable></a-image>'
    elif file_type == 'mp4':
        return f'<a-video position="{position}" src="#{Path(file_path).stem}" width="1" height="1" class="raycastable" draggable></a-video>'
    return ''

def encode_file(file_path):
    with open(file_path, "rb") as file:
        return base64.b64encode(file.read()).decode()

def main():
    st.set_page_config(layout="wide")
    
    with st.sidebar:
        st.title("3D File Viewer ๐ŸŒ")
        
        st.markdown("### ๐ŸŽจ Create Assets")
        st.markdown("[Open 3D Animation Toolkit](https://huggingface.co/spaces/awacke1/3d_animation_toolkit)", unsafe_allow_html=True)
        
        st.markdown("### ๐Ÿ“ Directory")
        directory = st.text_input("Enter path:", ".", key="directory_input")
        
        st.markdown("### โฌ†๏ธ Upload")
        uploaded_files = st.file_uploader("Add files:", accept_multiple_files=True, key="file_uploader")
        
        st.markdown("### โ„น๏ธ Instructions")
        st.write("- Click and drag to move objects")
        st.write("- Use mouse wheel to zoom")
        st.write("- Right-click and drag to rotate")

    if not os.path.isdir(directory):
        st.sidebar.error("Invalid directory path")
        return

    file_types = ['obj', 'glb', 'webp', 'png', 'mp4']
    
    if uploaded_files:
        for uploaded_file in uploaded_files:
            file_extension = Path(uploaded_file.name).suffix.lower()[1:]
            if file_extension in file_types:
                with open(os.path.join(directory, uploaded_file.name), "wb") as f:
                    shutil.copyfileobj(uploaded_file, f)
                st.sidebar.success(f"Uploaded: {uploaded_file.name}")
            else:
                st.sidebar.warning(f"Skipped unsupported file: {uploaded_file.name}")

    files = [f for f in os.listdir(directory) if f.split('.')[-1] in file_types]

    aframe_scene = """
    <a-scene embedded style="height: 600px; width: 100%;">
      <a-entity camera="userHeight: 1.6" position="0 2 2" rotation="-45 0 0" cursor="rayOrigin: mouse" raycaster="objects: .raycastable"></a-entity>
    """

    assets = "<a-assets>"
    entities = ""

    for i, file in enumerate(files):
        file_path = os.path.join(directory, file)
        file_type = file.split('.')[-1]
        encoded_file = encode_file(file_path)
        
        if file_type in ['obj', 'glb']:
            assets += f'<a-asset-item id="{Path(file).stem}" src="data:application/octet-stream;base64,{encoded_file}"></a-asset-item>'
        elif file_type in ['webp', 'png', 'mp4']:
            mime_type = f"image/{file_type}" if file_type in ['webp', 'png'] else "video/mp4"
            assets += f'<{file_type} id="{Path(file).stem}" src="data:{mime_type};base64,{encoded_file}"></{file_type}>'

        position = f"{i} 0 {i}"
        entities += create_aframe_entity(file_path, file_type, position)

    assets += "</a-assets>"
    aframe_scene += assets + entities + "</a-scene>"

    st.components.v1.html(load_aframe_and_extras() + aframe_scene, height=600)

if __name__ == "__main__":
    main()