Spaces:
Runtime error
Runtime error
Commit
·
4251a28
1
Parent(s):
1be0bd5
adjustment
Browse files
src/app/render.ts
CHANGED
@@ -72,7 +72,7 @@ export async function newRender({
|
|
72 |
prompt,
|
73 |
// nbFrames: 8 and nbSteps: 15 --> ~10 sec generation
|
74 |
nbFrames, // when nbFrames is 1, we will only generate static images
|
75 |
-
nbSteps: isForVideo ?
|
76 |
actionnables,
|
77 |
segmentation: "firstframe", // one day we will remove this param, to make it automatic
|
78 |
width: isForVideo ? 576 : 1024,
|
@@ -121,7 +121,7 @@ export async function getRender(renderId: string) {
|
|
121 |
}
|
122 |
|
123 |
try {
|
124 |
-
console.log(`calling GET ${apiUrl}/render with renderId: ${renderId}`)
|
125 |
const res = await fetch(`${apiUrl}/render/${renderId}`, {
|
126 |
method: "GET",
|
127 |
headers: {
|
|
|
72 |
prompt,
|
73 |
// nbFrames: 8 and nbSteps: 15 --> ~10 sec generation
|
74 |
nbFrames, // when nbFrames is 1, we will only generate static images
|
75 |
+
nbSteps: isForVideo ? 30 : 35, // 20 = fast, 30 = better, 50 = best
|
76 |
actionnables,
|
77 |
segmentation: "firstframe", // one day we will remove this param, to make it automatic
|
78 |
width: isForVideo ? 576 : 1024,
|
|
|
121 |
}
|
122 |
|
123 |
try {
|
124 |
+
// console.log(`calling GET ${apiUrl}/render with renderId: ${renderId}`)
|
125 |
const res = await fetch(`${apiUrl}/render/${renderId}`, {
|
126 |
method: "GET",
|
127 |
headers: {
|
src/components/business/cartesian-image.tsx
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
-
import {
|
2 |
-
|
3 |
import { SceneEventHandler } from "./types"
|
4 |
import { RenderedScene } from "@/app/types"
|
|
|
5 |
|
6 |
-
export
|
7 |
rendered,
|
8 |
onEvent,
|
9 |
className,
|
@@ -13,23 +13,36 @@ export const CartesianImage = forwardRef(({
|
|
13 |
onEvent: SceneEventHandler
|
14 |
className?: string
|
15 |
debug?: boolean
|
16 |
-
}
|
17 |
|
18 |
-
const
|
19 |
|
20 |
-
|
|
|
21 |
|
22 |
-
if (!
|
23 |
console.log("element isn't ready")
|
24 |
return
|
25 |
}
|
26 |
|
27 |
-
const boundingRect =
|
28 |
-
const x = (event.clientX - boundingRect.left) * 1.03
|
29 |
-
const y = (event.clientY - boundingRect.top) //* 1.03
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
const eventType = isClick ? "click" : "hover"
|
32 |
-
onEvent(eventType,
|
33 |
}
|
34 |
|
35 |
if (!rendered.assetUrl) {
|
@@ -38,20 +51,18 @@ export const CartesianImage = forwardRef(({
|
|
38 |
return (
|
39 |
<div
|
40 |
className={className}
|
41 |
-
onMouseUp={(event) => handleEvent(event, true)}
|
42 |
-
onMouseMove={(event) => handleEvent(event, false)}
|
43 |
>
|
44 |
<img
|
45 |
src={rendered.assetUrl || undefined}
|
46 |
-
ref={ref
|
47 |
className="absolute"
|
|
|
|
|
48 |
/>
|
49 |
{debug && <img
|
50 |
src={rendered.maskUrl || undefined}
|
51 |
-
className="absolute opacity-50"
|
52 |
/>}
|
53 |
</div>
|
54 |
)
|
55 |
-
}
|
56 |
-
|
57 |
-
CartesianImage.displayName = "CartesianImage"
|
|
|
1 |
+
import { useRef } from "react"
|
|
|
2 |
import { SceneEventHandler } from "./types"
|
3 |
import { RenderedScene } from "@/app/types"
|
4 |
+
import { useImageDimension } from "@/lib/useImageDimension"
|
5 |
|
6 |
+
export function CartesianImage({
|
7 |
rendered,
|
8 |
onEvent,
|
9 |
className,
|
|
|
13 |
onEvent: SceneEventHandler
|
14 |
className?: string
|
15 |
debug?: boolean
|
16 |
+
}) {
|
17 |
|
18 |
+
const maskDimension = useImageDimension(rendered.maskUrl)
|
19 |
|
20 |
+
const ref = useRef<HTMLImageElement>(null)
|
21 |
+
const handleEvent = async (event: React.MouseEvent<HTMLImageElement, MouseEvent>, isClick: boolean) => {
|
22 |
|
23 |
+
if (!ref.current) {
|
24 |
console.log("element isn't ready")
|
25 |
return
|
26 |
}
|
27 |
|
28 |
+
const boundingRect = ref.current.getBoundingClientRect()
|
29 |
+
// const x = (event.clientX - boundingRect.left) * 1.03
|
30 |
+
// const y = (event.clientY - boundingRect.top) //* 1.03
|
31 |
+
|
32 |
+
// those X and Y will be based on the current size of the container, which might be variable
|
33 |
+
const containerX = event.clientX - boundingRect.left
|
34 |
+
const containerY = event.clientY - boundingRect.top
|
35 |
+
|
36 |
+
// then we convert them to relative coordinates
|
37 |
+
const relativeX = containerX / boundingRect.width
|
38 |
+
const relativey = containerY / boundingRect.height
|
39 |
+
|
40 |
+
// finally, we convert back to coordinates within the input image
|
41 |
+
const imageX = relativeX * maskDimension.width
|
42 |
+
const imageY = relativey * maskDimension.height
|
43 |
|
44 |
const eventType = isClick ? "click" : "hover"
|
45 |
+
onEvent(eventType, imageX, imageY)
|
46 |
}
|
47 |
|
48 |
if (!rendered.assetUrl) {
|
|
|
51 |
return (
|
52 |
<div
|
53 |
className={className}
|
|
|
|
|
54 |
>
|
55 |
<img
|
56 |
src={rendered.assetUrl || undefined}
|
57 |
+
ref={ref}
|
58 |
className="absolute"
|
59 |
+
onMouseUp={(event) => handleEvent(event, true)}
|
60 |
+
onMouseMove={(event) => handleEvent(event, false)}
|
61 |
/>
|
62 |
{debug && <img
|
63 |
src={rendered.maskUrl || undefined}
|
64 |
+
className="absolute opacity-50 pointer-events-none"
|
65 |
/>}
|
66 |
</div>
|
67 |
)
|
68 |
+
}
|
|
|
|
src/components/business/cartesian-video.tsx
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
-
import {
|
2 |
-
|
3 |
import { SceneEventHandler } from "./types"
|
4 |
import { RenderedScene } from "@/app/types"
|
|
|
5 |
|
6 |
-
export
|
7 |
rendered,
|
8 |
onEvent,
|
9 |
className,
|
@@ -13,49 +13,58 @@ export const CartesianVideo = forwardRef(({
|
|
13 |
onEvent: SceneEventHandler
|
14 |
className?: string
|
15 |
debug?: boolean
|
16 |
-
}
|
17 |
-
|
18 |
-
const handleEvent = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, isClick: boolean) => {
|
19 |
|
20 |
-
|
|
|
21 |
|
22 |
-
if (!
|
23 |
console.log("element isn't ready")
|
24 |
return
|
25 |
}
|
26 |
|
27 |
-
const boundingRect =
|
28 |
-
const x = event.clientX - boundingRect.left
|
29 |
-
const y = event.clientY - boundingRect.top
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
const eventType = isClick ? "click" : "hover"
|
32 |
-
onEvent(eventType,
|
33 |
}
|
34 |
|
35 |
return (
|
36 |
-
<div
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
/>}
|
57 |
-
</div>
|
58 |
)
|
59 |
-
}
|
60 |
-
|
61 |
-
CartesianVideo.displayName = "CartesianVideo"
|
|
|
1 |
+
import { useRef } from "react"
|
|
|
2 |
import { SceneEventHandler } from "./types"
|
3 |
import { RenderedScene } from "@/app/types"
|
4 |
+
import { useImageDimension } from "@/lib/useImageDimension"
|
5 |
|
6 |
+
export function CartesianVideo({
|
7 |
rendered,
|
8 |
onEvent,
|
9 |
className,
|
|
|
13 |
onEvent: SceneEventHandler
|
14 |
className?: string
|
15 |
debug?: boolean
|
16 |
+
}) {
|
17 |
+
const maskDimension = useImageDimension(rendered.maskUrl)
|
|
|
18 |
|
19 |
+
const ref = useRef<HTMLVideoElement>(null)
|
20 |
+
const handleEvent = (event: React.MouseEvent<HTMLVideoElement, MouseEvent>, isClick: boolean) => {
|
21 |
|
22 |
+
if (!ref.current) {
|
23 |
console.log("element isn't ready")
|
24 |
return
|
25 |
}
|
26 |
|
27 |
+
const boundingRect = ref.current.getBoundingClientRect()
|
28 |
+
// const x = (event.clientX - boundingRect.left) * 1.03
|
29 |
+
// const y = (event.clientY - boundingRect.top) //* 1.03
|
30 |
+
|
31 |
+
// those X and Y will be based on the current size of the container, which might be variable
|
32 |
+
const containerX = event.clientX - boundingRect.left
|
33 |
+
const containerY = event.clientY - boundingRect.top
|
34 |
+
|
35 |
+
// then we convert them to relative coordinates
|
36 |
+
const relativeX = containerX / boundingRect.width
|
37 |
+
const relativey = containerY / boundingRect.height
|
38 |
+
|
39 |
+
// finally, we convert back to coordinates within the input image
|
40 |
+
// TODO: go read the video size
|
41 |
+
const contentX = relativeX * maskDimension.width
|
42 |
+
const contentY = relativey * maskDimension.height
|
43 |
|
44 |
const eventType = isClick ? "click" : "hover"
|
45 |
+
onEvent(eventType, contentX, contentY)
|
46 |
}
|
47 |
|
48 |
return (
|
49 |
+
<div className={className}>
|
50 |
+
<video
|
51 |
+
src={rendered.assetUrl || undefined}
|
52 |
+
ref={ref}
|
53 |
+
onMouseUp={(event) => handleEvent(event, true)}
|
54 |
+
onMouseMove={(event) => handleEvent(event, false)}
|
55 |
+
className="absolute"
|
56 |
+
muted
|
57 |
+
autoPlay
|
58 |
+
loop
|
59 |
+
width="1024px"
|
60 |
+
height="512px"
|
61 |
+
/>
|
62 |
+
{debug && <img
|
63 |
+
src={rendered.maskUrl || undefined}
|
64 |
+
className="absolute opacity-50 pointer-events-none"
|
65 |
+
width="1024px"
|
66 |
+
height="512px"
|
67 |
+
/>}
|
68 |
+
</div>
|
|
|
|
|
69 |
)
|
70 |
+
}
|
|
|
|
src/components/business/renderer.tsx
CHANGED
@@ -27,7 +27,6 @@ export const Renderer = ({
|
|
27 |
debug: boolean
|
28 |
}) => {
|
29 |
const timeoutRef = useRef<any>()
|
30 |
-
const viewRef = useRef<HTMLDivElement>()
|
31 |
const canvasRef = useRef<HTMLCanvasElement | null>(null)
|
32 |
const contextRef = useRef<CanvasRenderingContext2D | null>(null)
|
33 |
const [actionnable, setActionnable] = useState<string>("")
|
@@ -192,20 +191,17 @@ export const Renderer = ({
|
|
192 |
{engine.type === "cartesian_video"
|
193 |
? <CartesianVideo
|
194 |
rendered={rendered}
|
195 |
-
ref={viewRef as any}
|
196 |
onEvent={handleMouseEvent}
|
197 |
debug={debug}
|
198 |
/>
|
199 |
: engine.type === "spherical_image"
|
200 |
? <SphericalImage
|
201 |
rendered={rendered}
|
202 |
-
ref={viewRef as any}
|
203 |
onEvent={handleMouseEvent}
|
204 |
debug={debug}
|
205 |
/>
|
206 |
: <CartesianImage
|
207 |
rendered={rendered}
|
208 |
-
ref={viewRef as any}
|
209 |
onEvent={handleMouseEvent}
|
210 |
debug={debug}
|
211 |
/>
|
|
|
27 |
debug: boolean
|
28 |
}) => {
|
29 |
const timeoutRef = useRef<any>()
|
|
|
30 |
const canvasRef = useRef<HTMLCanvasElement | null>(null)
|
31 |
const contextRef = useRef<CanvasRenderingContext2D | null>(null)
|
32 |
const [actionnable, setActionnable] = useState<string>("")
|
|
|
191 |
{engine.type === "cartesian_video"
|
192 |
? <CartesianVideo
|
193 |
rendered={rendered}
|
|
|
194 |
onEvent={handleMouseEvent}
|
195 |
debug={debug}
|
196 |
/>
|
197 |
: engine.type === "spherical_image"
|
198 |
? <SphericalImage
|
199 |
rendered={rendered}
|
|
|
200 |
onEvent={handleMouseEvent}
|
201 |
debug={debug}
|
202 |
/>
|
203 |
: <CartesianImage
|
204 |
rendered={rendered}
|
|
|
205 |
onEvent={handleMouseEvent}
|
206 |
debug={debug}
|
207 |
/>
|
src/components/business/spherical-image.tsx
CHANGED
@@ -1,10 +1,9 @@
|
|
1 |
-
import { ForwardedRef, forwardRef } from "react"
|
2 |
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer"
|
3 |
|
4 |
import { SceneEventHandler } from "./types"
|
5 |
import { RenderedScene } from "@/app/types"
|
6 |
|
7 |
-
export
|
8 |
rendered,
|
9 |
onEvent,
|
10 |
className,
|
@@ -14,7 +13,7 @@ export const SphericalImage = forwardRef(({
|
|
14 |
onEvent: SceneEventHandler
|
15 |
className?: string
|
16 |
debug?: boolean
|
17 |
-
}
|
18 |
|
19 |
if (!rendered.assetUrl) {
|
20 |
return null
|
@@ -32,6 +31,21 @@ export const SphericalImage = forwardRef(({
|
|
32 |
|
33 |
defaultZoomLvl={1}
|
34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
onClick={(data, instance) => {
|
36 |
console.log("on click:")
|
37 |
const position = data.target.getPosition()
|
@@ -59,6 +73,4 @@ export const SphericalImage = forwardRef(({
|
|
59 |
|
60 |
/>
|
61 |
)
|
62 |
-
}
|
63 |
-
|
64 |
-
SphericalImage.displayName = "SphericalImage"
|
|
|
|
|
1 |
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer"
|
2 |
|
3 |
import { SceneEventHandler } from "./types"
|
4 |
import { RenderedScene } from "@/app/types"
|
5 |
|
6 |
+
export function SphericalImage({
|
7 |
rendered,
|
8 |
onEvent,
|
9 |
className,
|
|
|
13 |
onEvent: SceneEventHandler
|
14 |
className?: string
|
15 |
debug?: boolean
|
16 |
+
}) {
|
17 |
|
18 |
if (!rendered.assetUrl) {
|
19 |
return null
|
|
|
31 |
|
32 |
defaultZoomLvl={1}
|
33 |
|
34 |
+
overlay={rendered.maskUrl || undefined}
|
35 |
+
overlayOpacity={debug ? 0.5 : 0}
|
36 |
+
|
37 |
+
panoData={{
|
38 |
+
fullWidth: 1300,
|
39 |
+
fullHeight: 700,
|
40 |
+
croppedWidth: 1024,
|
41 |
+
croppedHeight: 512,
|
42 |
+
croppedX: 0,
|
43 |
+
croppedY: 120,
|
44 |
+
// poseHeading: 0, // 0 to 360
|
45 |
+
posePitch: 0, // -90 to 90
|
46 |
+
// poseRoll: 0, // -180 to 180
|
47 |
+
}}
|
48 |
+
|
49 |
onClick={(data, instance) => {
|
50 |
console.log("on click:")
|
51 |
const position = data.target.getPosition()
|
|
|
73 |
|
74 |
/>
|
75 |
)
|
76 |
+
}
|
|
|
|
src/lib/getImageDimension.ts
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export interface ImageDimension {
|
2 |
+
width: number
|
3 |
+
height: number
|
4 |
+
}
|
5 |
+
|
6 |
+
export async function getImageDimension(src: string): Promise<ImageDimension> {
|
7 |
+
if (!src) {
|
8 |
+
return { width: 0, height: 0 }
|
9 |
+
}
|
10 |
+
const img = new Image()
|
11 |
+
img.src = src
|
12 |
+
await img.decode()
|
13 |
+
const width = img.width
|
14 |
+
const height = img.height
|
15 |
+
return { width, height }
|
16 |
+
}
|
src/lib/useImageDimension.ts
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useEffect, useState } from "react"
|
2 |
+
|
3 |
+
import { ImageDimension, getImageDimension } from "./getImageDimension"
|
4 |
+
|
5 |
+
export function useImageDimension(src: string) {
|
6 |
+
const [dimension, setDimension] = useState<ImageDimension>({
|
7 |
+
width: 0,
|
8 |
+
height: 0,
|
9 |
+
})
|
10 |
+
|
11 |
+
useEffect(() => {
|
12 |
+
const compute = async () => {
|
13 |
+
const newDimension = await getImageDimension(src)
|
14 |
+
setDimension(newDimension)
|
15 |
+
}
|
16 |
+
compute()
|
17 |
+
}, [src])
|
18 |
+
|
19 |
+
return dimension
|
20 |
+
}
|