spritePropertyGridComponent.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import * as React from "react";
  2. import { Observable } from "babylonjs/Misc/observable";
  3. import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
  4. import { LockObject } from "../lockObject";
  5. import { LineContainerComponent } from '../../../lineContainerComponent';
  6. import { GlobalState } from '../../../../globalState';
  7. import { TextInputLineComponent } from '../../../lines/textInputLineComponent';
  8. import { TextLineComponent } from '../../../../../sharedUiComponents/lines/textLineComponent';
  9. import { Sprite } from 'babylonjs/Sprites/sprite';
  10. import { CheckBoxLineComponent } from '../../../lines/checkBoxLineComponent';
  11. import { Vector3LineComponent } from '../../../lines/vector3LineComponent';
  12. import { Color4LineComponent } from '../../../lines/color4LineComponent';
  13. import { FloatLineComponent } from '../../../lines/floatLineComponent';
  14. import { SliderLineComponent } from '../../../lines/sliderLineComponent';
  15. import { ButtonLineComponent } from '../../../../../sharedUiComponents/lines/buttonLineComponent';
  16. import { TextureHelper } from '../../../../../textureHelper';
  17. import { Nullable } from 'babylonjs/types';
  18. interface ISpritePropertyGridComponentProps {
  19. globalState: GlobalState;
  20. sprite: Sprite;
  21. lockObject: LockObject;
  22. onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
  23. onSelectionChangedObservable?: Observable<any>;
  24. }
  25. export class SpritePropertyGridComponent extends React.Component<ISpritePropertyGridComponentProps> {
  26. private canvasRef: React.RefObject<HTMLCanvasElement>;
  27. private imageData: Nullable<Uint8Array> = null;
  28. private cachedCellIndex = -1;
  29. constructor(props: ISpritePropertyGridComponentProps) {
  30. super(props);
  31. this.canvasRef = React.createRef();
  32. }
  33. onManagerLink() {
  34. if (!this.props.onSelectionChangedObservable) {
  35. return;
  36. }
  37. const sprite = this.props.sprite;
  38. this.props.onSelectionChangedObservable.notifyObservers(sprite.manager);
  39. }
  40. switchPlayStopState() {
  41. const sprite = this.props.sprite;
  42. if (sprite.animationStarted) {
  43. sprite.stopAnimation();
  44. } else {
  45. sprite.playAnimation(sprite.fromIndex, sprite.toIndex, sprite.loopAnimation, sprite.delay, () => {});
  46. }
  47. this.forceUpdate();
  48. }
  49. disposeSprite() {
  50. const sprite = this.props.sprite;
  51. sprite.dispose();
  52. this.props.onSelectionChangedObservable?.notifyObservers(null);
  53. }
  54. componentDidMount() {
  55. this.updatePreview();
  56. }
  57. componentDidUpdate() {
  58. this.updatePreview();
  59. }
  60. shouldComponentUpdate(nextProps: ISpritePropertyGridComponentProps) {
  61. if (nextProps.sprite !== this.props.sprite) {
  62. this.imageData = null;
  63. }
  64. return true;
  65. }
  66. updatePreview() {
  67. const sprite = this.props.sprite;
  68. const manager = sprite.manager;
  69. var texture = manager.texture;
  70. var size = texture.getSize();
  71. if (!this.imageData) {
  72. TextureHelper.GetTextureDataAsync(texture, size.width, size.height, 0, {R: true, G:true, B:true, A:true}, this.props.globalState).then(data => {
  73. this.imageData = data;
  74. this.forceUpdate();
  75. });
  76. return;
  77. }
  78. if (this.cachedCellIndex === sprite.cellIndex) {
  79. return;
  80. }
  81. this.cachedCellIndex = sprite.cellIndex;
  82. const previewCanvas = this.canvasRef.current as HTMLCanvasElement;
  83. previewCanvas.width = manager.cellWidth;
  84. previewCanvas.height = manager.cellHeight;
  85. var context = previewCanvas.getContext('2d');
  86. if (context) {
  87. // Copy the pixels to the preview canvas
  88. var imageData = context.createImageData(manager.cellWidth, manager.cellHeight);
  89. var castData = imageData.data;
  90. let rowLength = size.width / manager.cellWidth | 0;
  91. let offsetY = sprite.cellIndex / rowLength | 0;
  92. let offsetX = sprite.cellIndex - offsetY * rowLength;
  93. let offset = (offsetX + offsetY * size.width) * 4 * manager.cellWidth ;
  94. for (var x = 0; x < manager.cellWidth; x++) {
  95. for (var y = 0; y < manager.cellHeight; y++) {
  96. let targetCoord = (x + y * manager.cellWidth) * 4;
  97. let sourceCoord = (x + y * size.width) * 4
  98. castData[targetCoord] = this.imageData[offset + sourceCoord];
  99. castData[targetCoord + 1] = this.imageData[offset + sourceCoord + 1];
  100. castData[targetCoord + 2] = this.imageData[offset + sourceCoord + 2];
  101. castData[targetCoord + 3] = this.imageData[offset + sourceCoord + 3];
  102. }
  103. }
  104. context.putImageData(imageData, 0, 0);
  105. }
  106. }
  107. render() {
  108. const sprite = this.props.sprite;
  109. const manager = sprite.manager;
  110. const textureSize = manager.texture.getSize();
  111. let maxCellCount = 0;
  112. if (!textureSize.width || !textureSize.height) {
  113. maxCellCount = Math.max(sprite.fromIndex, sprite.toIndex);
  114. } else {
  115. maxCellCount = (textureSize.width / manager.cellWidth) * (textureSize.height / manager.cellHeight);
  116. }
  117. return (
  118. <div className="pane">
  119. <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
  120. <TextInputLineComponent lockObject={this.props.lockObject} label="Name" target={sprite} propertyName="name" onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  121. <TextLineComponent label="Unique ID" value={sprite.uniqueId.toString()} />
  122. <TextLineComponent label="Link to manager" value={manager.name} onLink={() => this.onManagerLink()} />
  123. <CheckBoxLineComponent label="Visible" target={sprite} propertyName="isVisible" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  124. <ButtonLineComponent label="Dispose" onClick={() => this.disposeSprite()} />
  125. </LineContainerComponent>
  126. <LineContainerComponent globalState={this.props.globalState} title="PROPERTIES">
  127. <Vector3LineComponent label="Position" target={sprite} propertyName="position" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  128. <CheckBoxLineComponent label="Pickable" target={sprite} propertyName="isPickable" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  129. <CheckBoxLineComponent label="Use alpha for picking" target={sprite} propertyName="useAlphaForPicking" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  130. <Color4LineComponent label="Color" target={sprite} propertyName="color" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  131. <SliderLineComponent useEuler={this.props.globalState.onlyUseEulers} label="Angle" target={sprite} propertyName="angle" minimum={0} maximum={2 * Math.PI} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  132. </LineContainerComponent>
  133. <LineContainerComponent globalState={this.props.globalState} title="CELL">
  134. <canvas ref={this.canvasRef} className="preview" style={{
  135. margin: "auto",
  136. marginTop: "4px",
  137. marginBottom: "4px",
  138. display: "grid",
  139. height: "108px"
  140. }}/>
  141. <SliderLineComponent label="Cell index" decimalCount={0} target={sprite} propertyName="cellIndex" minimum={0} maximum={maxCellCount} step={1} onPropertyChangedObservable={this.props.onPropertyChangedObservable}
  142. onChange={() => this.forceUpdate()}
  143. />
  144. <CheckBoxLineComponent label="Invert U axis" target={sprite} propertyName="invertU" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  145. <CheckBoxLineComponent label="Invert V axis" target={sprite} propertyName="invertV" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  146. </LineContainerComponent>
  147. <LineContainerComponent globalState={this.props.globalState} title="SCALE">
  148. <FloatLineComponent label="Width" lockObject={this.props.lockObject} target={sprite} propertyName="width" min={0} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  149. <FloatLineComponent label="Height" lockObject={this.props.lockObject} target={sprite} propertyName="height" min={0} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  150. </LineContainerComponent>
  151. <LineContainerComponent globalState={this.props.globalState} title="ANIMATION">
  152. <FloatLineComponent label="Start cell" isInteger={true} lockObject={this.props.lockObject} target={sprite} propertyName="fromIndex" min={0} max={maxCellCount} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  153. <FloatLineComponent label="End cell" isInteger={true} lockObject={this.props.lockObject} target={sprite} propertyName="toIndex" min={0} max={maxCellCount} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  154. <CheckBoxLineComponent label="Loop" target={sprite} propertyName="loopAnimation" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  155. <FloatLineComponent label="Delay" lockObject={this.props.lockObject} target={sprite} propertyName="delay" digits={0} min={0} isInteger={true} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  156. <ButtonLineComponent label={sprite.animationStarted ? "Stop" : "Start"} onClick={() => this.switchPlayStopState()} />
  157. </LineContainerComponent>
  158. </div>
  159. );
  160. }
  161. }