Skip to content

Commit

Permalink
Merge branch '3dmodel'
Browse files Browse the repository at this point in the history
  • Loading branch information
grifdail committed Nov 22, 2024
2 parents b9033d5 + a118efe commit d0713f1
Show file tree
Hide file tree
Showing 13 changed files with 325 additions and 6 deletions.
81 changes: 81 additions & 0 deletions src/Components/Settings/ModelUploadSetting.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { SettingComponent, SettingProps } from "./SettingsComponents";
import { ButtonGroup } from "../StyledComponents/ButtonGroup";
import styled from "styled-components";
import { IconFileUpload } from "@tabler/icons-react";
import { useDropzone } from "react-dropzone";
import { Button } from "../Generics/Button";

const Body = styled.div`
width: 100%;
height: 100%;
display: flex;
justify-content: stretch;
align-items: stretch;
flex-direction: column;
padding: 0;
margin: 0;
& > div.loaded,
& > div.file,
& img {
flex-grow: 1;
display: block flex;
object-fit: contain;
justify-content: center;
align-items: center;
background: var(--gradient-transparent);
max-height: 180px;
}
& svg {
height: 50%;
width: 50%;
}
`;

export const ModelUploadSetting: SettingComponent = function ({ onChange, value, def }: SettingProps) {
const { getRootProps, getInputProps } = useDropzone({
onDrop: (acceptedFiles, fileRejection) => {
console.log(acceptedFiles, fileRejection);
if (acceptedFiles.length >= 1) {
var file = acceptedFiles[0];

const reader = new FileReader();

reader.onabort = () => console.log("file reading was aborted");
reader.onerror = () => console.log("file reading has failed");

reader.onload = () => {
console.log(reader.result, file.name.split(".").pop());
onChange({ source: reader.result, ext: file.name.split(".").pop(), name: file.name });
};
reader.readAsText(file);
}
},
accept: { "model/obj": [".obj"] },
maxFiles: 1,
});

return (
<Body>
{value === null && (
<div
className="file"
{...getRootProps()}>
<input {...getInputProps()}></input>
<IconFileUpload />
</div>
)}
{value !== null && <div className="loaded">loaded {value.name}</div>}

<ButtonGroup hidden={value !== null}>
<Button
label="Reset"
onClick={() => onChange(null)}></Button>
</ButtonGroup>
</Body>
);
};
ModelUploadSetting.getSize = function (value, def): number {
return 250;
};
2 changes: 2 additions & 0 deletions src/Components/Settings/SettingsComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ImagePaintSetting } from "./ImagePaintSetting";
import { NodeData } from "../../Types/NodeData";
import { ButtonsSettings } from "./ButtonsSettings";
import { AnimationTrackSettings } from "./AnimationTrackSettings";
import { ModelUploadSetting } from "./ModelUploadSetting";
import { EasingSetting } from "./EasingPreview";
import { CodeBlockSetting } from "./CodeBlockSetting";

Expand Down Expand Up @@ -42,6 +43,7 @@ export const SettingComponents: { [key in SettingType]: SettingComponent } = {
hidden: EmptySetting,
buttons: ButtonsSettings,
animationTrack: AnimationTrackSettings,
"mesh-upload": ModelUploadSetting,
"easing-preview": EasingSetting,
"code-block": CodeBlockSetting,
};
1 change: 1 addition & 0 deletions src/Components/SketchPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const sketch: Sketch<MySketchProps> = (p5) => {
var context: ExecutionContext = createExecutionContext(tree, p5 as P5CanvasInstance);
var seed = 0;

console.log(p5.VERSION);
p5.setup = () => {};

p5.updateWithProps = (props: MySketchProps) => {
Expand Down
11 changes: 10 additions & 1 deletion src/Components/StyledComponents/PortColor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Icon, IconArrowUpRightCircle, IconColorSwatch, IconNumber2, IconNumber3, IconNumber4, IconNumbers, IconPaint, IconPalette, IconPhoto, IconPlayerPlayFilled, IconQuestionMark, IconQuote, IconToggleLeft } from "@tabler/icons-react";
import { Icon, IconArrowUpRightCircle, IconColorSwatch, IconCube, IconNumber2, IconNumber3, IconNumber4, IconNumbers, IconPaint, IconPalette, IconPhoto, IconPlayerPlayFilled, IconQuestionMark, IconQuote, IconToggleLeft } from "@tabler/icons-react";

import { PortType } from "../../Types/PortType";
import { NumberInput } from "../Generics/Inputs/NumberInput";
Expand Down Expand Up @@ -73,6 +73,11 @@ export const PortColor: { [key in PortType]: PortColorDefinition } = {
input: MaterialInput,
tinyIcon: IconPaint,
},
mesh: {
icon: IconCube,
input: undefined,
tinyIcon: IconCube,
},
unknown: {
icon: IconQuestionMark,
input: undefined,
Expand Down Expand Up @@ -122,4 +127,8 @@ export const PortColor: { [key in PortType]: PortColorDefinition } = {
icon: IconArrowUpRightCircle,
tinyIcon: IconNumber4,
},
"array-mesh": {
icon: IconCube,
tinyIcon: IconCube,
},
};
65 changes: 65 additions & 0 deletions src/Nodes/3D/DrawModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { IconCube } from "@tabler/icons-react";
import { NodeDefinition } from "../../Types/NodeDefinition";
import { createVector3 } from "../../Types/vectorDataType";
import { createDefaultMaterial } from "../../Utils/createDefaultMaterial";

export const DrawModel: NodeDefinition = {
id: "DrawModel",
label: "Draw Model",
description: "Draw a 3d model",
icon: IconCube,
tags: ["3D", "Draw"],
dataInputs: [
{
id: "material",
type: "material",
defaultValue: createDefaultMaterial(),
},
{
id: "position",
type: "vector3",
defaultValue: createVector3(0, 0, 0),
},
{
id: "dimension",
type: "vector3",
defaultValue: createVector3(1, 1, 1),
},
{
id: "rotation",
type: "vector3",
defaultValue: createVector3(0, 0, 0),
},
{
id: "model",
type: "mesh",
defaultValue: null,
},
],
dataOutputs: [],
executeOutputs: [],
settings: [],
canBeExecuted: true,
execute: (data, context) => {
var model = context.getInputValueModel(data, "model");
if (model == null) {
return;
}
var material = context.getInputValueMaterial(data, "material");

var rotation = context.getInputValueVector3(data, "rotation");
var position = context.getInputValueVector3(data, "position");
var dimension = context.getInputValueVector3(data, "dimension");
context.target.push();
context.target.translate(...position);
context.target.rotateZ(rotation[2]);
context.target.rotateX(rotation[0]);
context.target.rotateY(rotation[1]);
context.target.scale(...dimension);
if (material) {
context.applyMaterial(material);
}
context.target.model(model);
context.target.pop();
},
};
115 changes: 115 additions & 0 deletions src/Nodes/Array/GenerateUVModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { IconList, IconPlus } from "@tabler/icons-react";
import p5 from "p5";
import { useTree } from "../../Hooks/useTree";
import { NodeData } from "../../Types/NodeData";
import { NodeDefinition } from "../../Types/NodeDefinition";
import { createVector2, createVector3 } from "../../Types/vectorDataType";

const createIndexNode = ({ id, positionX, positionY }: NodeData): void => {
setTimeout(() => {
useTree.getState().createBlackboardNode(
[
{
type: "vector2",
key: `${id}-uv`,
id: "uv",
},
],
"Generate UV",
positionX - 400,
positionY,
id
);
}, 10);
};

export const GenerateUVModel: NodeDefinition = {
id: "GenerateUVModel",
description: "Generate a 3D model by mapping a set of 2d coordinate to 3d one",
featureLevel: 0,
icon: IconList,
tags: ["3D"],
dataInputs: [{ id: "pos", type: "vector3", defaultValue: createVector3(0, 0, 0) }],
dataOutputs: [{ id: "model", type: "mesh", defaultValue: null }],
executeOutputs: [],
settings: [
{
id: "width",
type: "number",
defaultValue: 10,
},
{
id: "height",
type: "number",
defaultValue: 10,
},
{ id: "when", type: "dropdown", defaultValue: "Once", options: ["Once", "Per frame", "Everytime"] },
{
id: "buttons",
type: "buttons",
defaultValue: undefined,
buttons: [
{
label: "Create UV node",
icon: IconPlus,
onClick: createIndexNode,
},
],
},
],
canBeExecuted: false,
contextMenu: {
"Create the UV node": createIndexNode,
},
getData: (portId, node, context) => {
const when = node.settings.when;
const keyCache = `${node.id}-image-cache`;
const keyComputed = `${node.id}-is-computed`;
let model = context.blackboard[keyCache];

let needRedraw = model === null;
needRedraw ||= when === "Once" && !context.blackboard[keyComputed];
needRedraw ||= when === "Per frame" && !context.frameBlackboard[keyComputed];
needRedraw ||= when === "Everytime";
if (needRedraw) {
const width = node.settings.width;
const height = node.settings.height;
const uvKey = `${node.id}-uv`;
const firstRun = model == null;
model = !firstRun ? model : new p5.Geometry(width, height);

for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
var uv = createVector2(x / (width - 1), y / (height - 1));
context.blackboard[uvKey] = uv;
var pos = context.getInputValueVector3(node, "pos");
const selfId = y * width + x;
model.vertices[selfId] = new p5.Vector(pos[0], pos[1], pos[2]);

if (x > 0 && y > 0 && firstRun) {
const upId = (y - 1) * width + x;
const leftId = y * width + (x - 1);
const upLeftId = (y - 1) * width + (x - 1);
const side = (x + y) % 2 === 0;
if (side) {
model.faces.push([selfId, upId, leftId]);
model.faces.push([upId, upLeftId, leftId]);
} else {
model.faces.push([leftId, selfId, upLeftId]);
model.faces.push([selfId, upId, upLeftId]);
}
}
}
}
model.computeNormals();
model.dirtyFlags.vertices = true;
model.dirtyFlags.vertexNormals = true;
context.blackboard[keyCache] = model;
context.blackboard[keyComputed] = true;
context.frameBlackboard[keyComputed] = true;
return model;
}

return model;
},
};
31 changes: 31 additions & 0 deletions src/Nodes/Images/UploadModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { IconPhoto } from "@tabler/icons-react";
import p5 from "p5";
import { NodeDefinition } from "../../Types/NodeDefinition";

export const UploadModel: NodeDefinition = {
id: "UploadModel",
label: "Upload Model",
icon: IconPhoto,
description: "Upload a 3d Model",
dataInputs: [],
dataOutputs: [{ id: "model", type: "mesh", defaultValue: null }],
tags: ["3d"],
executeOutputs: [],
settings: [{ id: "model", type: "mesh-upload", defaultValue: null }],
getData(portId, data, context) {
if (data.settings.model != null) {
var key = `${data.id}-model-cache`;
if (!context.blackboard[key]) {
new p5((p5) => {
const model = p5.createModel(data.settings.model.source, data.settings.model.ext);
context.blackboard[key] = model;
});
return null;
} else {
return context.blackboard[key];
}
}

return;
},
};
6 changes: 6 additions & 0 deletions src/Nodes/Nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import { createConstant } from "./createConstant";
import { DrawBox } from "./3D/DrawBox";
import { DrawCilinder } from "./3D/DrawCilinder";
import { DrawCone } from "./3D/DrawCone";
import { DrawModel } from "./3D/DrawModel";
import { DrawPlane } from "./3D/DrawPlane";
import { DrawSphere } from "./3D/DrawSphere";
import { DrawTorus } from "./3D/DrawTorus";
Expand All @@ -110,6 +111,7 @@ import { Count } from "./Array/Count";
import { Filter } from "./Array/Filter";
import { FindBest } from "./Array/FindBest";
import { GenerateArray } from "./Array/GenerateArray";
import { GenerateUVModel } from "./Array/GenerateUVModel";
import { SelectFromArray } from "./Array/SelectFromArray";
import { Slice } from "./Array/Slice";
import { StaticArray } from "./Array/StaticArray";
Expand All @@ -124,6 +126,7 @@ import { BlurEffect } from "./Effects/BlurEffect";
import { DrawImagePart } from "./Images/DrawImagePart";
import { ImageDimension } from "./Images/ImageDimension";
import { PaintImage } from "./Images/PaintImage";
import { UploadModel } from "./Images/UploadModel";
import { RandomInt } from "./Inputs/RandomInt";
import { RandomOnSphere } from "./Inputs/RandomOnSphere";
import { Select } from "./Logic/SelectNode";
Expand Down Expand Up @@ -370,6 +373,9 @@ export const Nodes: Array<NodeDefinition> = [
DrawTorus,
DrawCone,
DrawCilinder,
UploadModel,
DrawModel,
GenerateUVModel,
//Materials
ExecuteWithLight,
RegularMaterial,
Expand Down
6 changes: 3 additions & 3 deletions src/Types/PortType.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
export type BasePortType = "number" | "vector2" | "color" | "string" | "bool" | "image" | "gradient" | "vector" | "vector3" | "vector4" | "material";
export type BasePortType = "number" | "vector2" | "color" | "string" | "bool" | "image" | "gradient" | "vector" | "vector3" | "vector4" | "material" | "mesh";
export type PortType = "execute" | BasePortType | `array-${BasePortType}` | "unknown";
export const BasePortTypeArray: PortType[] = ["number", "vector2", "color", "string", "bool", "image", "gradient", "vector3", "vector4", "material"];
export const BasePortTypeArray: PortType[] = ["number", "vector2", "color", "string", "bool", "image", "gradient", "vector3", "vector4", "material", "mesh"];
export const PortTypeArray: PortType[] = [...BasePortTypeArray, ...BasePortTypeArray.map((key) => `array-${key}` as PortType)];
export const VectorTypesFull: PortType[] = ["number", "vector2", "vector3", "color"];
export const VectorTypesPosition: PortType[] = ["number", "vector2", "vector3", "vector4"];
export const VectorTypeslimited: PortType[] = ["vector2", "vector3"];
export const VectorLength: { [key: string]: number } = { number: 1, vector2: 2, vector3: 3, vector4: 4, color: 4 };
export const CommonTypes: BasePortType[] = ["number", "vector2", "vector3", "color", "gradient", "image", "string", "material", "bool"];
export const CommonTypes: BasePortType[] = ["number", "vector2", "vector3", "color", "gradient", "image", "string", "material", "bool", "mesh"];
export const ArrayCommonTypes: PortType[] = CommonTypes.map((key) => `array-${key}` as PortType);
export const FullCommonTypes = [...CommonTypes, ...ArrayCommonTypes];
export const ArrayTypes: PortType[] = BasePortTypeArray.map((key) => `array-${key}` as PortType);
Expand Down
2 changes: 1 addition & 1 deletion src/Types/SettingType.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export type SettingType = "dropdown" | "palette" | "number" | "gradient" | "image-upload" | "image-paint" | "envelope" | "string" | "hidden" | "buttons" | "animationTrack" | "easing-preview" | "code-block";
export type SettingType = "dropdown" | "palette" | "number" | "gradient" | "image-upload" | "image-paint" | "envelope" | "string" | "hidden" | "buttons" | "animationTrack" | "mesh-upload" | "easing-preview" | "code-block";
Loading

0 comments on commit d0713f1

Please sign in to comment.