@@ -2,125 +2,38 @@ import React, { useEffect, useRef } from 'react';
2
2
import { environment } from '#store/environment' ;
3
3
import { observer } from 'mobx-react' ;
4
4
import { exportSprite } from '#formats/image' ;
5
- import { rotateImageData , getRotateDiagonal } from '#util/rotsprite' ;
6
- import { Input , Slider , Item , Button , Modal } from '#ui' ;
5
+ import { rotsprite , threeShears } from '#util/rotsprite' ;
6
+ import { Input , Slider , Item , Button , Modal , Select } from '#ui' ;
7
7
import { mappingState } from './state' ;
8
8
9
9
import { importState } from '../import/state' ;
10
10
11
- function rotateCurrentSprite ( canvas , angle ) {
11
+ function rotateCurrentSprite ( canvas , angle , algorithm ) {
12
12
const spriteCanv = exportSprite ( environment . currentSprite ) ;
13
- const spriteCtx = spriteCanv . getContext ( '2d' ) ;
14
- // const { width, height } = spriteCanv;
15
- // const imageData = spriteCtx.getImageData(0, 0, width, height);
16
- // const rotatedData = rotateImageData(imageData, angle, width, height);
17
13
18
- // const ctx = canvas.getContext('2d');
19
- // canvas.width = rotatedData.width;
20
- // canvas.height = rotatedData.height;
21
- // ctx.putImageData(rotatedData, 0, 0);
22
-
23
- function flipImageData ( imageData ) {
24
- const { width, height, data } = imageData ;
25
- const rotatedImageData = new ImageData ( width , height ) ;
26
- const rotatedData = rotatedImageData . data ;
27
-
28
- for ( let y = 0 ; y < height ; y ++ ) {
29
- for ( let x = 0 ; x < width ; x ++ ) {
30
- const srcIndex = ( y * width + x ) * 4 ;
31
- const dstIndex = ( ( height - y - 1 ) * width + ( width - x - 1 ) ) * 4 ;
32
- rotatedData [ dstIndex + 0 ] = data [ srcIndex + 0 ] ;
33
- rotatedData [ dstIndex + 1 ] = data [ srcIndex + 1 ] ;
34
- rotatedData [ dstIndex + 2 ] = data [ srcIndex + 2 ] ;
35
- rotatedData [ dstIndex + 3 ] = data [ srcIndex + 3 ] ;
36
- }
37
- }
38
-
39
- return rotatedImageData ;
40
- }
41
-
42
- const flipped = angle > 90 && angle < 270 ;
43
- // TODO: fix flip clipping
44
- // TODO: fix padding clipping
45
-
46
- let { diagonal, xMargin, yMargin } = getRotateDiagonal (
47
- spriteCanv . width ,
48
- spriteCanv . height ,
49
- ) ;
50
- const width = diagonal ;
51
- const height = diagonal ;
52
-
53
- const copy = spriteCtx . getImageData (
54
- 0 ,
55
- 0 ,
56
- spriteCanv . width ,
57
- spriteCanv . height ,
58
- ) ;
59
-
60
- spriteCanv . width = diagonal ;
61
- spriteCanv . height = diagonal ;
62
-
63
- spriteCtx . putImageData ( flipped ? flipImageData ( copy ) : copy , xMargin , yMargin ) ;
64
-
65
- const ctx = canvas . getContext ( '2d' ) ;
66
- canvas . width = width ;
67
- canvas . height = height ;
68
-
69
-
70
- if ( flipped ) {
71
- // // flip spriteCanv using ctx as a buffer
72
- // ctx.save();
73
- // ctx.translate(width / 2, height / 2);
74
- // ctx.rotate(Math.PI);
75
- // ctx.drawImage(spriteCanv, -width / 2, -width / 2);
76
- // ctx.restore();
77
- // spriteCtx.clearRect(0, 0, width, height);
78
- // spriteCtx.drawImage(canvas, 0, 0, width, height);
79
- // ctx.clearRect(0, 0, width, height);
14
+ if ( algorithm === 'rotsprite' ) {
15
+ rotsprite ( spriteCanv , canvas , angle ) ;
16
+ } else {
17
+ threeShears ( spriteCanv , canvas , angle ) ;
80
18
}
81
19
82
- // rotate
83
-
84
- const clampedAngle = flipped ? angle - 180 : angle ;
85
- const theta = ( clampedAngle * Math . PI ) / 180 ;
86
- const alpha = - Math . tan ( theta / 2 ) ;
87
- const beta = Math . sin ( theta ) ;
88
-
89
- for ( let y = 0 ; y < height ; ++ y ) {
90
- const shear = Math . round ( ( y - height / 2 ) * alpha ) ;
91
- ctx . drawImage ( spriteCanv , 0 , y , width , 1 , shear , y , width , 1 ) ;
92
- }
93
- spriteCtx . clearRect ( 0 , 0 , width , height ) ;
94
- spriteCtx . drawImage ( canvas , 0 , 0 ) ;
95
- ctx . clearRect ( 0 , 0 , width , height ) ;
96
- for ( let x = 0 ; x < width ; ++ x ) {
97
- const shear = Math . round ( ( x - width / 2 ) * beta ) ;
98
- ctx . drawImage ( spriteCanv , x , 0 , 1 , height , x , shear , 1 , height ) ;
99
- }
100
- spriteCtx . clearRect ( 0 , 0 , width , height ) ;
101
- spriteCtx . drawImage ( canvas , 0 , 0 ) ;
102
- ctx . clearRect ( 0 , 0 , width , height ) ;
103
- for ( let y = 0 ; y < height ; ++ y ) {
104
- const shear = Math . round ( ( y - height / 2 ) * alpha ) ;
105
- ctx . drawImage ( spriteCanv , 0 , y , width , 1 , shear , y , width , 1 ) ;
106
- }
107
20
}
108
21
109
22
export const Rotate = observer ( ( ) => {
110
23
const canvasRef = useRef ( ) ;
111
24
112
- const { active, angle } = mappingState . rotate ;
25
+ const { active, angle, algorithm } = mappingState . rotate ;
113
26
114
27
useEffect ( ( ) => {
115
28
if ( ! canvasRef . current ) {
116
29
requestAnimationFrame ( ( ) => {
117
30
canvasRef . current &&
118
- rotateCurrentSprite ( canvasRef . current , angle ) ;
31
+ rotateCurrentSprite ( canvasRef . current , angle , algorithm ) ;
119
32
} ) ;
120
33
return ;
121
34
}
122
- rotateCurrentSprite ( canvasRef . current , angle ) ;
123
- } , [ environment . currentSprite , angle , active ] ) ;
35
+ rotateCurrentSprite ( canvasRef . current , angle , algorithm ) ;
36
+ } , [ environment . currentSprite , angle , active , algorithm ] ) ;
124
37
125
38
const assertInput = ( num ) => {
126
39
const value = Math . max ( 0 , Math . min ( 360 , num ) ) ;
@@ -142,7 +55,14 @@ export const Rotate = observer(() => {
142
55
opacity : active ? 1 : 0 ,
143
56
} }
144
57
>
58
+ < div className = "row" >
145
59
< Item > Rotate Sprite</ Item >
60
+ < Select
61
+ options = { mappingState . rotateAlgOptions }
62
+ store = { mappingState . rotate }
63
+ accessor = "algorithm"
64
+ />
65
+ </ div >
146
66
< canvas ref = { canvasRef } />
147
67
< div className = "angles" >
148
68
< div className = "numbers" >
@@ -177,7 +97,7 @@ export const Rotate = observer(() => {
177
97
</ div >
178
98
< div className = "actions" >
179
99
< Button color = "magenta" onClick = { mappingState . toggleRotate } >
180
- close
100
+ Close
181
101
</ Button >
182
102
< Button color = "red" onClick = { reImport } >
183
103
Import
0 commit comments