textureLinkLineComponent.tsx 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import * as React from "react";
  2. import { Nullable } from "babylonjs/types";
  3. import { Observable, Observer } from "babylonjs/Misc/observable";
  4. import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
  5. import { Material } from "babylonjs/Materials/material";
  6. import { StandardMaterial } from "babylonjs/Materials/standardMaterial";
  7. import { TextLineComponent } from "./textLineComponent";
  8. import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
  9. import { faWrench, faTrash } from '@fortawesome/free-solid-svg-icons';
  10. import { Texture } from 'babylonjs/Materials/Textures/texture';
  11. import { FileButtonLineComponent } from './fileButtonLineComponent';
  12. import { Tools } from 'babylonjs/Misc/tools';
  13. export interface ITextureLinkLineComponentProps {
  14. label: string;
  15. texture: Nullable<BaseTexture>;
  16. material?: Material;
  17. onSelectionChangedObservable?: Observable<any>;
  18. onDebugSelectionChangeObservable?: Observable<TextureLinkLineComponent>;
  19. propertyName?: string;
  20. onTextureCreated?: (texture: BaseTexture) => void;
  21. customDebugAction?: (state: boolean) => void
  22. onTextureRemoved?: () => void;
  23. }
  24. export class TextureLinkLineComponent extends React.Component<ITextureLinkLineComponentProps, { isDebugSelected: boolean }> {
  25. private _onDebugSelectionChangeObserver: Nullable<Observer<TextureLinkLineComponent>>;
  26. constructor(props: ITextureLinkLineComponentProps) {
  27. super(props);
  28. const material = this.props.material;
  29. const texture = this.props.texture;
  30. this.state = { isDebugSelected: material && material.reservedDataStore && material.reservedDataStore.debugTexture === texture };
  31. }
  32. componentDidMount() {
  33. if (!this.props.onDebugSelectionChangeObservable) {
  34. return;
  35. }
  36. this._onDebugSelectionChangeObserver = this.props.onDebugSelectionChangeObservable.add((line) => {
  37. if (line !== this) {
  38. this.setState({ isDebugSelected: false });
  39. }
  40. });
  41. }
  42. componentWillUnmount() {
  43. if (this.props.onDebugSelectionChangeObservable && this._onDebugSelectionChangeObserver) {
  44. this.props.onDebugSelectionChangeObservable.remove(this._onDebugSelectionChangeObserver);
  45. }
  46. }
  47. debugTexture() {
  48. if (this.props.customDebugAction) {
  49. let newState = !this.state.isDebugSelected;
  50. this.props.customDebugAction(newState);
  51. this.setState({ isDebugSelected: newState });
  52. if (this.props.onDebugSelectionChangeObservable) {
  53. this.props.onDebugSelectionChangeObservable.notifyObservers(this);
  54. }
  55. return;
  56. }
  57. const texture = this.props.texture;
  58. const material = this.props.material;
  59. if (!material || !texture) {
  60. return;
  61. }
  62. const scene = material.getScene();
  63. if (material.reservedDataStore && material.reservedDataStore.debugTexture === texture) {
  64. const debugMaterial = material.reservedDataStore.debugMaterial;
  65. texture.level = material.reservedDataStore.level;
  66. for (var mesh of scene.meshes) {
  67. if (mesh.material === debugMaterial) {
  68. mesh.material = material;
  69. }
  70. }
  71. debugMaterial.dispose();
  72. material.reservedDataStore.debugTexture = null;
  73. material.reservedDataStore.debugMaterial = null;
  74. this.setState({ isDebugSelected: false });
  75. return;
  76. }
  77. let checkMaterial = material;
  78. let needToDisposeCheckMaterial = false;
  79. if (material.reservedDataStore && material.reservedDataStore.debugTexture) {
  80. checkMaterial = material.reservedDataStore.debugMaterial;
  81. needToDisposeCheckMaterial = true;
  82. }
  83. var debugMaterial = new StandardMaterial("debugMaterial", scene);
  84. debugMaterial.disableLighting = true;
  85. debugMaterial.sideOrientation = material.sideOrientation;
  86. debugMaterial.emissiveTexture = texture;
  87. debugMaterial.forceDepthWrite = true;
  88. debugMaterial.reservedDataStore = { hidden: true };
  89. for (var mesh of scene.meshes) {
  90. if (mesh.material === checkMaterial) {
  91. mesh.material = debugMaterial;
  92. }
  93. }
  94. if (!material.reservedDataStore) {
  95. material.reservedDataStore = {};
  96. }
  97. material.reservedDataStore.debugTexture = texture;
  98. material.reservedDataStore.debugMaterial = debugMaterial;
  99. material.reservedDataStore.level = texture.level;
  100. texture.level = 1.0;
  101. if (this.props.onDebugSelectionChangeObservable) {
  102. this.props.onDebugSelectionChangeObservable.notifyObservers(this);
  103. }
  104. if (needToDisposeCheckMaterial) {
  105. checkMaterial.dispose();
  106. }
  107. this.setState({ isDebugSelected: true });
  108. }
  109. onLink() {
  110. if (!this.props.onSelectionChangedObservable) {
  111. return;
  112. }
  113. const texture = this.props.texture;
  114. this.props.onSelectionChangedObservable.notifyObservers(texture!);
  115. }
  116. updateTexture(file: File) {
  117. let material = this.props.material!;
  118. Tools.ReadFile(file, (data) => {
  119. var blob = new Blob([data], { type: "octet/stream" });
  120. var url = URL.createObjectURL(blob);
  121. let texture = new Texture(url, material.getScene(), false, false);
  122. if (this.props.propertyName) {
  123. (material as any)[this.props.propertyName!] = texture;
  124. } else if (this.props.onTextureCreated) {
  125. this.props.onTextureCreated(texture);
  126. }
  127. this.forceUpdate();
  128. }, undefined, true);
  129. }
  130. removeTexture() {
  131. let material = this.props.material!;
  132. if (this.props.propertyName) {
  133. (material as any)[this.props.propertyName!] = null;
  134. } else if (this.props.onTextureRemoved) {
  135. this.props.onTextureRemoved();
  136. }
  137. this.forceUpdate();
  138. }
  139. render() {
  140. const texture = this.props.texture;
  141. if (!texture) {
  142. if (this.props.propertyName || this.props.onTextureCreated) {
  143. return (
  144. <FileButtonLineComponent label={`Add ${this.props.label} texture`} onClick={(file) => this.updateTexture(file)} accept=".jpg, .png, .tga, .dds, .env" />
  145. )
  146. }
  147. return null;
  148. }
  149. return (
  150. <div className="textureLinkLine">
  151. {
  152. !texture.isCube && this.props.material &&
  153. <>
  154. <div className={this.state.isDebugSelected ? "debug selected" : "debug"}>
  155. <span className="actionIcon" onClick={() => this.debugTexture()} title="Render as main texture">
  156. <FontAwesomeIcon icon={faWrench} />
  157. </span>
  158. <span className="actionIcon" onClick={() => this.removeTexture()} title="Remove texture">
  159. <FontAwesomeIcon icon={faTrash} />
  160. </span>
  161. </div>
  162. </>
  163. }
  164. <TextLineComponent label={this.props.label} value={texture.name} onLink={() => this.onLink()} />
  165. </div>
  166. );
  167. }
  168. }