Skip to content

Commit

Permalink
Merge pull request #110 from franciscohermida/feature/simple-editor
Browse files Browse the repository at this point in the history
feat: simple editor
  • Loading branch information
JaimeTorrealba committed Apr 17, 2024
2 parents 9795fb0 + 68cab32 commit 45fcf95
Show file tree
Hide file tree
Showing 16 changed files with 941 additions and 0 deletions.
33 changes: 33 additions & 0 deletions components/content/simple-editor/ContainElement.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script setup lang="ts">
import { useElementSize, useParentElement } from '@vueuse/core'
const props = defineProps({
enabled: { type: Boolean, default: true },
aspectRatio: { type: Number, required: true },
})
const containerRef = ref<HTMLElement | null>(null)
const parentElementRef = useParentElement()
const { width, height } = useElementSize(parentElementRef)
const containerAspectRatio = computed(() => width.value / height.value)
const isLandscape = computed(() => props.aspectRatio < containerAspectRatio.value)
const containedWidth = computed(() => isLandscape.value ? height.value * props.aspectRatio : width.value)
const containedHeight = computed(() => isLandscape.value ? height.value : width.value / props.aspectRatio)
</script>

<template>
<div
ref="containerRef"
class="absolute"
:style="{
width: `${enabled ? containedWidth : width}px`,
height: `${enabled ? containedHeight : height}px`,
}"
>
<slot />
</div>
</template>

35 changes: 35 additions & 0 deletions components/content/simple-editor/CustomTresOrbitControls.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script setup lang="ts">
import { extend, useTresContext } from '@tresjs/core'
import { OrbitControls } from 'three-stdlib'
const props = defineProps({
enabled: {
type: Boolean,
default: true,
},
camera: {
type: Object,
},
})
const { camera: contextCamera, renderer } = useTresContext()
const orbitControlsRef = ref()
const internalCamera = computed(() => props.camera ?? contextCamera.value)
extend({ OrbitControls })
defineExpose({ value: orbitControlsRef })
</script>

<template>
<TresOrbitControls
v-if="renderer"
:key="internalCamera?.uuid"
ref="orbitControlsRef"
:args="[internalCamera, renderer?.domElement]"
:camera="internalCamera"
:enabled="enabled"
/>
</template>
36 changes: 36 additions & 0 deletions components/content/simple-editor/SceneNodeBox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
import { type Mesh, Color, MathUtils } from 'three'
import type { BoxSceneNode } from './types'
const props = defineProps({
properties: {
type: Object as PropType<BoxSceneNode['properties']>,
default: () => ({ width: 10, height: 10, length: 10 }),
},
first: { type: Boolean, default: false },
})
// weird bug happening if we don't explicitly emit click instead of letting it flow through
const emit = defineEmits(['click'])
const { properties } = toRefs(props)
const randomColor = new Color(MathUtils.randInt(0, 0xffffff))
const color = computed(() => props.first ? new Color('#535353') : randomColor)
const meshRef = ref<Mesh | null>()
defineExpose({ mesh: meshRef })
</script>

<template>
<TresMesh
ref="meshRef"
@click="emit('click')"
>
<TresBoxGeometry
:args="[properties.width, properties.height, properties.length]"
/>
<TresMeshBasicMaterial :color="color" />
</TresMesh>
</template>
44 changes: 44 additions & 0 deletions components/content/simple-editor/SceneNodeBoxProps.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<script setup lang="ts">
import type { BoxSceneNode } from './types'
const props = defineProps({
modelValue: {
type: Object as PropType<BoxSceneNode>,
required: true,
},
})
const emit = defineEmits(['update:modelValue'])
const { modelValue } = toRefs(props)
const internalModelValue = ref<BoxSceneNode>(structuredClone(toRaw(modelValue.value)))
watch(modelValue, () => {
internalModelValue.value = structuredClone(toRaw(modelValue.value))
})
function handleModelValueUpdate() {
emit('update:modelValue', structuredClone(toRaw(internalModelValue.value)))
}
</script>

<template>
<div class="grid grid-cols-[auto_auto] gap-1">
Width:
<input
v-model="internalModelValue.properties.width"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
Length:
<input
v-model="internalModelValue.properties.length"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
Height:
<input
v-model="internalModelValue.properties.height"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
</div>
</template>
32 changes: 32 additions & 0 deletions components/content/simple-editor/SceneNodeCameraProps.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script setup lang="ts">
import type { CameraSceneNode } from './types'
const props = defineProps({
modelValue: {
type: Object as PropType<CameraSceneNode>,
required: true,
validation: (val: CameraSceneNode) => val.type === 'camera',
},
})
const emit = defineEmits(['update:modelValue'])
const { modelValue } = toRefs(props)
const internalModelValue = ref<CameraSceneNode>(structuredClone(toRaw(modelValue.value)))
watch(modelValue, () => {
internalModelValue.value = structuredClone(toRaw(modelValue.value))
})
function handleModelValueUpdate() {
emit('update:modelValue', structuredClone(toRaw(internalModelValue.value)))
}
</script>

<template>
<div class="grid grid-cols-[auto_auto] gap-1">
Fov: <input
v-model="internalModelValue.properties.fov"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
</div>
</template>
36 changes: 36 additions & 0 deletions components/content/simple-editor/SceneNodeCone.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
import { type Object3D, Color, MathUtils } from 'three'
import type { ConeSceneNode } from './types'
const props = defineProps({
properties: {
type: Object as PropType<ConeSceneNode['properties']>,
default: () => ({ radius: 5, height: 10 }),
},
first: { type: Boolean, default: false },
})
// weird bug happening if we don't explicitly emit click instead of letting it flow through
const emit = defineEmits(['click'])
const { properties } = toRefs(props)
const randomColor = new Color(MathUtils.randInt(0, 0xffffff))
const color = computed(() => props.first ? new Color('#82dbc5') : randomColor)
const meshRef = ref<Object3D | null>()
defineExpose({ mesh: meshRef })
</script>

<template>
<TresMesh
ref="meshRef"
@click="emit('click')"
>
<TresConeGeometry
:args="[properties.radius, properties.height, 32, 16]"
/>
<TresMeshBasicMaterial :color="color" />
</TresMesh>
</template>
36 changes: 36 additions & 0 deletions components/content/simple-editor/SceneNodeConeProps.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
import type { ConeSceneNode } from './types'
const props = defineProps({
modelValue: {
type: Object as PropType<ConeSceneNode>,
required: true,
},
})
const emit = defineEmits(['update:modelValue'])
const { modelValue } = toRefs(props)
const internalModelValue = ref<ConeSceneNode>(structuredClone(toRaw(modelValue.value)))
watch(modelValue, () => {
internalModelValue.value = structuredClone(toRaw(modelValue.value))
})
function handleModelValueUpdate() {
emit('update:modelValue', structuredClone(toRaw(internalModelValue.value)))
}
</script>

<template>
<div class="grid grid-cols-[auto_auto] gap-1">
Radius: <input
v-model="internalModelValue.properties.radius"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
Height: <input
v-model="internalModelValue.properties.height"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
</div>
</template>
84 changes: 84 additions & 0 deletions components/content/simple-editor/SceneNodeProps.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<script setup lang="ts">
import type { SceneNode } from './types'
const props = defineProps({
modelValue: {
type: Object as PropType<SceneNode>,
required: true,
},
})
const emit = defineEmits(['update:modelValue'])
const { modelValue } = toRefs(props)
const internalModelValue = ref<SceneNode>(structuredClone(toRaw(modelValue.value)))
watch(modelValue, () => {
internalModelValue.value = structuredClone(toRaw(modelValue.value))
}, { deep: true })
function handleModelValueUpdate() {
emit('update:modelValue', structuredClone(toRaw(internalModelValue.value)))
}
</script>

<template>
<div>
Position:
<div class="grid grid-cols-[auto_auto] gap-1">
x: <input
v-model.number="internalModelValue.position[0]"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
y: <input
v-model.number="internalModelValue.position[1]"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
z: <input
v-model.number="internalModelValue.position[2]"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
</div>
</div>
<div>
Rotation:
<div class="grid grid-cols-[auto_auto] gap-1">
x: <input
v-model.number="internalModelValue.rotation[0]"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
y: <input
v-model.number="internalModelValue.rotation[1]"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
z: <input
v-model.number="internalModelValue.rotation[2]"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
</div>
</div>
<div>
Scale:
<div class="grid grid-cols-[auto_auto] gap-1">
x: <input
v-model.number="internalModelValue.scale[0]"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
y: <input
v-model.number="internalModelValue.scale[1]"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
z: <input
v-model.number="internalModelValue.scale[2]"
class="dark:text-black"
@update:model-value="handleModelValueUpdate"
>
</div>
</div>
</template>
36 changes: 36 additions & 0 deletions components/content/simple-editor/SceneNodeSphere.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
import { type Object3D, Color, MathUtils } from 'three'
import type { SphereSceneNode } from './types'
const props = defineProps({
properties: {
type: Object as PropType<SphereSceneNode['properties']>,
default: () => ({ radius: 5 }),
},
first: { type: Boolean, default: false },
})
// weird bug happening if we don't explicitly emit click instead of letting it flow through
const emit = defineEmits(['click'])
const { properties } = toRefs(props)
const randomColor = new Color(MathUtils.randInt(0, 0xffffff))
const color = computed(() => props.first ? new Color('#efac35') : randomColor)
const meshRef = ref<Object3D | null>()
defineExpose({ mesh: meshRef })
</script>

<template>
<TresMesh
ref="meshRef"
@click="emit('click')"
>
<TresSphereGeometry
:args="[properties.radius, 32, 16]"
/>
<TresMeshBasicMaterial :color="color" />
</TresMesh>
</template>
Loading

0 comments on commit 45fcf95

Please sign in to comment.