TextureEditor.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { LabelElement, ToggleInput, SelectInput } from '../../libs/flow.module.js';
  2. import { BaseNode, onNodeValidElement } from '../core/BaseNode.js';
  3. import { TextureNode, UVNode } from 'three-nodes/Nodes.js';
  4. import { Texture, TextureLoader, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping } from 'three';
  5. const fileTexture = new WeakMap();
  6. const textureLoader = new TextureLoader();
  7. const defaultTexture = new Texture();
  8. const defaultUV = new UVNode();
  9. const getTextureFromFile = ( file ) => {
  10. let texture = fileTexture.get( file );
  11. if ( texture === undefined ) {
  12. texture = textureLoader.load( URL.createObjectURL( file ) );
  13. fileTexture.set( file, texture );
  14. }
  15. return texture;
  16. };
  17. export class TextureEditor extends BaseNode {
  18. constructor() {
  19. const node = new TextureNode( defaultTexture );
  20. super( 'Texture', 4, node, 250 );
  21. this.texture = null;
  22. this._initFile();
  23. this._initParams();
  24. this.onValidElement = () => {};
  25. }
  26. _initFile() {
  27. const fileElement = new LabelElement( 'File' ).setInputColor( 'aqua' ).setInput( 1 );
  28. fileElement.onValid( ( source, target, stage ) => {
  29. const object = target.getObject();
  30. if ( object && ( object instanceof File ) === false ) {
  31. if ( stage === 'dragged' ) {
  32. const name = target.node.getName();
  33. this.editor.tips.error( `"${name}" is not a File.` );
  34. }
  35. return false;
  36. }
  37. } ).onConnect( () => {
  38. const file = fileElement.getLinkedObject();
  39. const node = this.value;
  40. this.texture = file ? getTextureFromFile( file ) : null;
  41. node.value = this.texture || defaultTexture;
  42. this.update();
  43. } );
  44. this.add( fileElement );
  45. }
  46. _initParams() {
  47. const uvField = new LabelElement( 'UV' ).setInput( 2 );
  48. uvField.onValid( onNodeValidElement ).onConnect( () => {
  49. const node = this.value;
  50. node.uvNode = uvField.getLinkedObject() || defaultUV;
  51. } );
  52. this.wrapSInput = new SelectInput( [
  53. { name: 'Repeat Wrapping', value: RepeatWrapping },
  54. { name: 'Clamp To Edge Wrapping', value: ClampToEdgeWrapping },
  55. { name: 'Mirrored Repeat Wrapping', value: MirroredRepeatWrapping }
  56. ], RepeatWrapping ).onChange( () => {
  57. this.update();
  58. } );
  59. this.wrapTInput = new SelectInput( [
  60. { name: 'Repeat Wrapping', value: RepeatWrapping },
  61. { name: 'Clamp To Edge Wrapping', value: ClampToEdgeWrapping },
  62. { name: 'Mirrored Repeat Wrapping', value: MirroredRepeatWrapping }
  63. ], RepeatWrapping ).onChange( () => {
  64. this.update();
  65. } );
  66. this.flipYInput = new ToggleInput( false ).onClick( () => {
  67. this.update();
  68. } );
  69. this.add( uvField )
  70. .add( new LabelElement( 'Wrap S' ).add( this.wrapSInput ) )
  71. .add( new LabelElement( 'Wrap T' ).add( this.wrapTInput ) )
  72. .add( new LabelElement( 'Flip Y' ).add( this.flipYInput ) );
  73. }
  74. update() {
  75. const texture = this.texture;
  76. if ( texture ) {
  77. texture.wrapS = Number( this.wrapSInput.getValue() );
  78. texture.wrapT = Number( this.wrapTInput.getValue() );
  79. texture.flipY = this.flipYInput.getValue();
  80. texture.dispose();
  81. this.invalidate();
  82. }
  83. }
  84. }