3 unit uTouch; |
3 unit uTouch; |
4 |
4 |
5 interface |
5 interface |
6 |
6 |
7 uses sysutils, math, uConsole, uVariables, SDLh, uTypes, uFloat, uConsts, uIO, uCommands, GLUnit, uCommandHandlers; |
7 uses sysutils, math, uConsole, uVariables, SDLh, uTypes, uFloat, uConsts, uIO, uCommands, GLUnit, uCommandHandlers; |
|
8 |
|
9 type |
|
10 Touch_Finger = record |
|
11 id : SDL_FingerId; |
|
12 x,y : LongInt; |
|
13 historicalX, historicalY : LongInt; |
|
14 timeSinceDown : Longword; |
|
15 end; |
8 |
16 |
9 procedure initModule; |
17 procedure initModule; |
10 |
18 |
11 |
19 |
12 procedure ProcessTouch; |
20 procedure ProcessTouch; |
13 procedure onTouchDown(x,y: Longword; pointerId: SDL_FingerId); |
21 procedure onTouchDown(x,y: Longword; pointerId: SDL_FingerId); |
14 procedure onTouchMotion(x,y: Longword; dx,dy: LongInt; pointerId: SDL_FingerId); |
22 procedure onTouchMotion(x,y: Longword; dx,dy: LongInt; pointerId: SDL_FingerId); |
15 procedure onTouchUp(x,y: Longword; pointerId: SDL_FingerId); |
23 procedure onTouchUp(x,y: Longword; pointerId: SDL_FingerId); |
16 function convertToCursor(scale: LongInt; xy: LongInt): LongInt; |
24 function convertToCursor(scale: LongInt; xy: LongInt): LongInt; |
17 procedure addFinger(x,y: Longword; id: SDL_FingerId); |
25 function addFinger(x,y: Longword; id: SDL_FingerId): Touch_Finger; |
18 procedure deleteFinger(id: SDL_FingerId); |
26 procedure deleteFinger(id: SDL_FingerId); |
19 procedure onTouchClick(x,y: Longword; pointerId: SDL_FingerId); |
27 procedure onTouchClick(finger: Touch_Finger); |
20 |
28 |
21 procedure aim(id: SDL_FingerId); |
29 function findFinger(id: SDL_FingerId): Touch_Finger; |
22 function isOnCurrentHog(id: SDL_FingerId): boolean; |
30 procedure aim(finger: Touch_Finger); |
23 function isOnFireButton(id: SDL_FingerId): boolean; |
31 function isOnCurrentHog(finger: Touch_Finger): boolean; |
24 procedure convertToWorldCoord(var x,y: hwFloat; id: SDL_FingerId); |
32 function isOnFireButton(finger: Touch_Finger): boolean; |
25 function fingerHasMoved(id: SDL_FingerId): boolean; |
33 procedure convertToWorldCoord(var x,y: hwFloat; finger: Touch_Finger); |
26 function calculateDelta(id1, id2: SDL_FingerId): hwFloat; |
34 function fingerHasMoved(finger: Touch_Finger): boolean; |
27 function getSecondPointer(id: SDL_FingerId): SDL_FingerId; |
35 function calculateDelta(finger1, finger2: Touch_Finger): hwFloat; |
|
36 function getSecondFinger(finger: Touch_Finger): Touch_Finger; |
28 implementation |
37 implementation |
29 |
38 |
30 const |
39 const |
31 clicktime = 200; |
40 clicktime = 200; |
32 var |
41 var |
33 leftButtonBoundary : LongInt; |
42 leftButtonBoundary : LongInt; |
34 rightButtonBoundary : LongInt; |
43 rightButtonBoundary : LongInt; |
35 topButtonBoundary : LongInt; |
44 topButtonBoundary : LongInt; |
36 |
45 |
37 pointerCount : Longword; |
46 pointerCount : Longword; |
38 xyCoord : array of LongInt; |
47 fingers: array of Touch_Finger; |
39 pointerIds : array of SDL_FingerId; |
|
40 timeSinceDown: array of Longword; |
|
41 historicalXY : array of LongInt; |
|
42 |
|
43 moveCursor : boolean; |
48 moveCursor : boolean; |
44 |
49 |
45 //Pinch to zoom |
50 //Pinch to zoom |
46 pinchSize : hwFloat; |
51 pinchSize : hwFloat; |
47 baseZoomValue: GLFloat; |
52 baseZoomValue: GLFloat; |
49 invertCursor : boolean; |
54 invertCursor : boolean; |
50 |
55 |
51 //aiming |
56 //aiming |
52 aiming, movingCrosshair: boolean; |
57 aiming, movingCrosshair: boolean; |
53 crosshairCommand: ShortString; |
58 crosshairCommand: ShortString; |
54 aimingPointerId: SDL_FingerId; |
|
55 targetAngle: LongInt; |
59 targetAngle: LongInt; |
56 |
60 |
57 stopFiring: boolean; |
61 stopFiring: boolean; |
58 |
62 |
59 //moving |
63 //moving |
60 stopLeft, stopRight, walkingLeft, walkingRight : boolean; |
64 stopLeft, stopRight, walkingLeft, walkingRight : boolean; |
|
65 procedure printFinger(finger: Touch_Finger); |
|
66 begin |
|
67 WriteToConsole(Format('id:%d, (%d,%d), (%d,%d), time: %d', [finger.id, finger.x, finger.y, finger.historicalX, finger.historicalY, finger.timeSinceDown])); |
|
68 end; |
|
69 |
61 |
70 |
62 procedure onTouchDown(x,y: Longword; pointerId: SDL_FingerId); |
71 procedure onTouchDown(x,y: Longword; pointerId: SDL_FingerId); |
63 begin |
72 var |
64 addFinger(x,y,pointerId); |
73 finger: Touch_Finger; |
65 xyCoord[pointerId*2] := convertToCursor(cScreenWidth,x); |
74 begin |
66 xyCoord[pointerId*2+1] := convertToCursor(cScreenHeight,y); |
75 finger:= addFinger(x,y,pointerId); |
67 |
76 finger.x := convertToCursor(cScreenWidth,x); |
68 |
77 finger.y := convertToCursor(cScreenHeight,y); |
|
78 |
|
79 printFinger(finger); |
69 case pointerCount of |
80 case pointerCount of |
70 1: |
81 1: |
71 begin |
82 begin |
72 moveCursor:= false; |
83 moveCursor:= false; |
73 if bShowAmmoMenu then |
84 if bShowAmmoMenu then |
74 begin |
85 begin |
75 moveCursor := true; |
86 moveCursor := true; |
76 exit; |
87 exit; |
77 end; |
88 end; |
78 |
89 |
79 if isOnCurrentHog(pointerId) then |
90 if isOnCurrentHog(finger) then |
80 begin |
91 begin |
81 aiming:= true; |
92 aiming:= true; |
82 exit; |
93 exit; |
83 end; |
94 end; |
84 |
95 |
85 if isOnFireButton(pointerId) then |
96 if isOnFireButton(finger) then |
86 begin |
97 begin |
87 stopFiring:= false; |
98 stopFiring:= false; |
88 ParseCommand('+attack', true); |
99 ParseCommand('+attack', true); |
89 exit; |
100 exit; |
90 end; |
101 end; |
91 if xyCoord[pointerId*2] < leftButtonBoundary then |
102 if finger.x < leftButtonBoundary then |
92 begin |
103 begin |
93 ParseCommand('+left', true); |
104 ParseCommand('+left', true); |
94 walkingLeft := true; |
105 walkingLeft := true; |
95 exit; |
106 exit; |
96 end; |
107 end; |
97 if xyCoord[pointerId*2] > rightButtonBoundary then |
108 if finger.x > rightButtonBoundary then |
98 begin |
109 begin |
99 ParseCommand('+right', true); |
110 ParseCommand('+right', true); |
100 walkingRight:= true; |
111 walkingRight:= true; |
101 exit; |
112 exit; |
102 end; |
113 end; |
103 WriteToConsole(Format('%d, %d', [xyCoord[pointerId*2+1], topButtonBoundary])); |
114 if finger.y < topButtonBoundary then |
104 if xyCoord[pointerId*2+1] < topButtonBoundary then |
|
105 begin |
115 begin |
106 ParseCommand('hjump', true); |
116 ParseCommand('hjump', true); |
107 exit; |
117 exit; |
108 end; |
118 end; |
109 moveCursor:= true; |
119 moveCursor:= true; |
111 2: |
121 2: |
112 begin |
122 begin |
113 aiming:= false; |
123 aiming:= false; |
114 stopFiring:= true; |
124 stopFiring:= true; |
115 |
125 |
116 pinchSize := calculateDelta(pointerId, getSecondPointer(pointerId)); |
126 pinchSize := calculateDelta(finger, getSecondFinger(finger)); |
117 baseZoomValue := ZoomValue |
127 baseZoomValue := ZoomValue |
118 end; |
128 end; |
119 end;//end case pointerCount of |
129 end;//end case pointerCount of |
120 end; |
130 end; |
121 |
131 |
122 procedure onTouchMotion(x,y: Longword;dx,dy: LongInt; pointerId: SDL_FingerId); |
132 procedure onTouchMotion(x,y: Longword;dx,dy: LongInt; pointerId: SDL_FingerId); |
123 var |
133 var |
124 secondId : SDL_FingerId; |
134 finger, secondFinger: Touch_Finger; |
125 currentPinchDelta, zoom : hwFloat; |
135 currentPinchDelta, zoom : hwFloat; |
126 begin |
136 begin |
127 xyCoord[pointerId*2] := convertToCursor(cScreenWidth, x); |
137 finger:= findFinger(pointerId); |
128 xyCoord[pointerId*2+1] := convertToCursor(cScreenHeight, y); |
138 finger.x := convertToCursor(cScreenWidth, x); |
|
139 finger.y := convertToCursor(cScreenHeight, y); |
129 |
140 |
130 case pointerCount of |
141 case pointerCount of |
131 1: |
142 1: |
132 begin |
143 begin |
133 if aiming then |
144 if aiming then |
134 begin |
145 begin |
135 aim(pointerId); |
146 aim(finger); |
136 exit |
147 exit |
137 end; |
148 end; |
138 if moveCursor then |
149 if moveCursor then |
139 if invertCursor then |
150 if invertCursor then |
140 begin |
151 begin |
177 ParseCommand('-right', true); |
187 ParseCommand('-right', true); |
178 walkingRight := false; |
188 walkingRight := false; |
179 end; |
189 end; |
180 end; |
190 end; |
181 |
191 |
182 procedure onTouchClick(x,y: Longword; pointerId: SDL_FingerId); |
192 procedure onTouchClick(finger: Touch_Finger); |
183 begin |
193 begin |
184 if bShowAmmoMenu then |
194 if bShowAmmoMenu then |
185 begin |
195 begin |
186 doPut(CursorPoint.X, CursorPoint.Y, false); |
196 doPut(CursorPoint.X, CursorPoint.Y, false); |
187 exit |
197 exit |
188 end; |
198 end; |
189 |
199 |
190 if isOnCurrentHog(pointerId) then |
200 if isOnCurrentHog(finger) then |
191 begin |
201 begin |
192 bShowAmmoMenu := true; |
202 bShowAmmoMenu := true; |
193 exit; |
203 exit; |
194 end; |
204 end; |
195 |
205 |
196 if xyCoord[pointerId*2+1] < topButtonBoundary then |
206 if finger.y < topButtonBoundary then |
197 begin |
207 begin |
198 ParseCommand('hjump', true); |
208 ParseCommand('hjump', true); |
199 exit; |
209 exit; |
200 end; |
210 end; |
201 end; |
211 end; |
202 |
212 |
203 procedure addFinger(x,y: Longword; id: SDL_FingerId); |
213 function addFinger(x,y: Longword; id: SDL_FingerId): Touch_Finger; |
204 var |
214 var |
205 index, tmp: Longword; |
215 xCursor, yCursor, index : LongInt; |
206 begin |
216 begin |
207 pointerCount := pointerCount + 1; |
|
208 |
|
209 //Check array sizes |
217 //Check array sizes |
210 if length(pointerIds) < pointerCount then setLength(pointerIds, length(pointerIds)*2); |
218 if length(fingers) < pointerCount then |
211 if length(xyCoord) < id*2+1 then |
219 begin |
212 begin |
220 setLength(fingers, length(fingers)*2); |
213 setLength(xyCoord, id*2+1); |
221 for index := length(fingers) div 2 to length(fingers) do fingers[index].id := -1; |
214 setLength(historicalXY, id*2+1); |
222 end; |
215 end; |
223 |
216 if length(timeSinceDown) < id then setLength(timeSinceDown, id); |
224 |
217 for index := 0 to pointerCount do //place the pointer ids as far back to the left as possible |
225 xCursor := convertToCursor(cScreenWidth, x); |
218 begin |
226 yCursor := convertToCursor(cScreenHeight, y); |
219 if pointerIds[index] = -1 then |
227 |
220 begin |
228 //on removing fingers all fingers are moved to the left, thus new fingers will be to the far right |
221 pointerIds[index] := id; |
229 //with dynamic arrays being zero based, 'far right' is the old pointerCount |
222 break; |
230 fingers[pointerCount].id := id; |
223 end; |
231 fingers[pointerCount].historicalX := xCursor; |
224 end; |
232 fingers[pointerCount].historicalY := yCursor; |
225 //set timestamp |
233 fingers[pointerCount].x := xCursor; |
226 timeSinceDown[id] := SDL_GetTicks; |
234 fingers[pointerCount].y := yCursor; |
227 historicalXY[id*2] := convertToCursor(cScreenWidth,x); |
235 fingers[pointerCount].timeSinceDown:= SDL_GetTicks; |
228 historicalXY[id*2+1] := convertToCursor(cScreenHeight,y); |
236 |
|
237 inc(pointerCount); |
|
238 addFinger:= fingers[pointerCount]; |
229 end; |
239 end; |
230 |
240 |
231 procedure deleteFinger(id: SDL_FingerId); |
241 procedure deleteFinger(id: SDL_FingerId); |
232 var |
242 var |
233 index, i : Longint; |
243 index : Longint; |
234 begin |
244 begin |
235 index := 0; |
245 |
|
246 dec(pointerCount); |
236 for index := 0 to pointerCount do |
247 for index := 0 to pointerCount do |
237 begin |
248 begin |
238 if pointerIds[index] = id then |
249 if fingers[index].id = id then |
239 begin |
250 begin |
240 pointerIds[index] := -1; |
251 //Check for onTouchevent |
|
252 if ((SDL_GetTicks - fingers[index].timeSinceDown) < clickTime) AND not(fingerHasMoved(fingers[index])) then |
|
253 onTouchClick(fingers[index]); |
|
254 fingers[index].id := -1; |
241 break; |
255 break; |
242 end; |
256 end; |
243 end; |
257 end; |
244 //put the last pointerId into the stop of the id to be removed, so that all pointerIds are to the far left |
258 //put the last finger into the spot of the finger to be removed, so that all fingers are packed to the far left |
245 for i := pointerCount downto index do |
259 if fingers[pointerCount].id = -1 then |
246 begin |
260 begin |
247 if pointerIds[i] <> -1 then |
261 fingers[index] := fingers[pointerCount]; |
248 begin |
262 fingers[pointerCount].id := -1; |
249 pointerIds[index] := pointerIds[i]; |
263 end; |
250 break; |
264 |
251 end; |
|
252 end; |
|
253 if ((SDL_GetTicks - timeSinceDown[id]) < clickTime) AND not(fingerHasMoved(id)) then onTouchClick(xyCoord[id*2], xyCoord[id*2+1], id); |
|
254 end; |
265 end; |
255 |
266 |
256 procedure ProcessTouch; |
267 procedure ProcessTouch; |
257 var |
268 var |
258 deltaAngle: LongInt; |
269 deltaAngle: LongInt; |
300 ParseCommand('-left', true); |
311 ParseCommand('-left', true); |
301 end; |
312 end; |
302 |
313 |
303 end; |
314 end; |
304 |
315 |
305 procedure aim(id: SDL_FingerId); |
316 function findFinger(id: SDL_FingerId): Touch_Finger; |
|
317 begin |
|
318 for findFinger in fingers do |
|
319 if (findFinger.id = -1) and (findFinger.id = id) then break; |
|
320 end; |
|
321 |
|
322 procedure aim(finger: Touch_Finger); |
306 var |
323 var |
307 hogX, hogY, touchX, touchY, deltaX, deltaY, tmpAngle: hwFloat; |
324 hogX, hogY, touchX, touchY, deltaX, deltaY, tmpAngle: hwFloat; |
308 tmp: ShortString; |
325 tmp: ShortString; |
309 begin |
326 begin |
310 if CurrentHedgehog^.Gear <> nil then |
327 if CurrentHedgehog^.Gear <> nil then |
311 begin |
328 begin |
312 hogX := CurrentHedgehog^.Gear^.X; |
329 hogX := CurrentHedgehog^.Gear^.X; |
313 hogY := CurrentHedgehog^.Gear^.Y; |
330 hogY := CurrentHedgehog^.Gear^.Y; |
314 |
331 |
315 convertToWorldCoord(touchX, touchY, id); |
332 convertToWorldCoord(touchX, touchY, finger); |
316 deltaX := hwAbs(TouchX-HogX); |
333 deltaX := hwAbs(TouchX-HogX); |
317 deltaY := (TouchY-HogY); |
334 deltaY := (TouchY-HogY); |
318 |
335 |
319 tmpAngle:= DeltaY / Distance(deltaX, deltaY) *_2048; |
336 tmpAngle:= DeltaY / Distance(deltaX, deltaY) *_2048; |
320 targetAngle:= (hwRound(tmpAngle) + 2048) div 2; |
337 targetAngle:= (hwRound(tmpAngle) + 2048) div 2; |
334 function convertToCursor(scale: LongInt; xy: LongInt): LongInt; |
351 function convertToCursor(scale: LongInt; xy: LongInt): LongInt; |
335 begin |
352 begin |
336 convertToCursor := round(xy/32768*scale) |
353 convertToCursor := round(xy/32768*scale) |
337 end; |
354 end; |
338 |
355 |
339 function isOnFireButton(id: SDL_FingerId): boolean; |
356 function isOnFireButton(finger: Touch_Finger): boolean; |
340 begin |
357 begin |
341 isOnFireButton:= (xyCoord[id*2] < 150) and (xyCoord[id*2+1] > 390); |
358 isOnFireButton:= (finger.x < 150) and (finger.y > 390); |
342 end; |
359 end; |
343 |
360 |
344 function isOnCurrentHog(id: SDL_FingerId): boolean; |
361 function isOnCurrentHog(finger: Touch_Finger): boolean; |
345 var |
362 var |
346 x,y, fingerX, fingerY : hwFloat; |
363 x,y, fingerX, fingerY : hwFloat; |
347 begin |
364 begin |
348 x := CurrentHedgehog^.Gear^.X; |
365 x := CurrentHedgehog^.Gear^.X; |
349 y := CurrentHedgehog^.Gear^.Y; |
366 y := CurrentHedgehog^.Gear^.Y; |
350 |
367 |
351 convertToWorldCoord(fingerX, fingerY, id); |
368 convertToWorldCoord(fingerX, fingerY, finger); |
352 isOnCurrentHog := Distance(fingerX-x, fingerY-y) < _20; |
369 isOnCurrentHog := Distance(fingerX-x, fingerY-y) < _20; |
353 end; |
370 end; |
354 |
371 |
355 procedure convertToWorldCoord(var x,y: hwFloat; id: SDL_FingerId); |
372 procedure convertToWorldCoord(var x,y: hwFloat; finger: Touch_Finger); |
356 begin |
373 begin |
357 //if x <> nil then |
374 //if x <> nil then |
358 x := int2hwFloat((xyCoord[id*2]-WorldDx) - (cScreenWidth div 2)); |
375 x := int2hwFloat((finger.x-WorldDx) - (cScreenWidth div 2)); |
359 //if y <> nil then |
376 //if y <> nil then |
360 y := int2hwFloat(xyCoord[id*2+1]-WorldDy); |
377 y := int2hwFloat(finger.y-WorldDy); |
361 end; |
378 end; |
362 |
379 |
363 //Method to calculate the distance this finger has moved since the downEvent |
380 //Method to calculate the distance this finger has moved since the downEvent |
364 function fingerHasMoved(id: SDL_FingerId): boolean; |
381 function fingerHasMoved(finger: Touch_Finger): boolean; |
365 begin |
382 begin |
366 // fingerHasMoved := hwAbs(DistanceI(xyCoord[id*2]-historicalXY[id*2], xyCoord[id*2+1]-historicalXY[id*2+1])) > int2hwFloat(2000); // is 1% movement |
383 fingerHasMoved := trunc(sqrt(Power(finger.X-finger.historicalX,2) + Power(finger.y-finger.historicalY, 2))) > 330; |
367 fingerHasMoved := trunc(sqrt(Power(xyCoord[id*2]-historicalXY[id*2],2) + Power(xyCoord[id*2+1]-historicalXY[id*2+1], 2))) > 330; |
384 end; |
368 end; |
385 |
369 |
386 function calculateDelta(finger1, finger2: Touch_Finger): hwFloat; |
370 function calculateDelta(id1, id2: SDL_FingerId): hwFloat; |
|
371 begin |
387 begin |
372 // calculateDelta := Distance(xyCoord[id2*2] - xyCoord[id1*2], xyCoord[id2*2+1] - xyCoord[id1*2+1]); |
388 // calculateDelta := Distance(xyCoord[id2*2] - xyCoord[id1*2], xyCoord[id2*2+1] - xyCoord[id1*2+1]); |
373 calculateDelta := int2hwFloat(trunc(sqrt(Power(xyCoord[id2*2]-xyCoord[id1*2],2) + Power(xyCoord[id2*2+1]-xyCoord[id1*2+1], 2)))); |
389 calculateDelta := int2hwFloat(trunc(sqrt(Power(finger2.x-finger1.x, 2) + Power(finger2.y-finger1.y, 2)))); |
374 end; |
390 end; |
375 |
391 |
376 // Under the premise that all pointer ids in pointerIds:SDL_FingerId are pack to the far left. |
392 // Under the premise that all pointer ids in pointerIds:SDL_FingerId are pack to the far left. |
377 // If the pointer to be ignored is not pointerIds[0] the second must be there |
393 // If the pointer to be ignored is not pointerIds[0] the second must be there |
378 function getSecondPointer(id: SDL_FingerId): SDL_FingerId; |
394 function getSecondFinger(finger: Touch_Finger): Touch_Finger; |
379 begin |
395 begin |
380 if pointerIds[0] = id then getSecondPointer := pointerIds[1] |
396 if fingers[0].id = finger.id then getSecondFinger := fingers[0] |
381 else getSecondPointer := pointerIds[0]; |
397 else getSecondFinger := fingers[1]; |
382 end; |
398 end; |
383 |
399 |
384 procedure initModule; |
400 procedure initModule; |
385 var |
401 var |
386 index: Longword; |
402 finger: Touch_Finger; |
387 begin |
403 begin |
388 setLength(xyCoord, 10); |
|
389 setLength(pointerIds, 5); |
|
390 setLength(timeSinceDown, 5); |
|
391 setLength(historicalXY, 10); |
|
392 for index := Low(xyCoord) to High(xyCoord) do xyCoord[index] := -1; |
|
393 for index := Low(pointerIds) to High(pointerIds) do pointerIds[index] := -1; |
|
394 movingCrosshair := false; |
404 movingCrosshair := false; |
395 stopFiring:= false; |
405 stopFiring:= false; |
396 walkingLeft := false; |
406 walkingLeft := false; |
397 walkingRight := false; |
407 walkingRight := false; |
398 |
408 |
399 leftButtonBoundary := cScreenWidth div 4; |
409 leftButtonBoundary := cScreenWidth div 4; |
400 rightButtonBoundary := cScreenWidth div 4*3; |
410 rightButtonBoundary := cScreenWidth div 4*3; |
401 topButtonBoundary := cScreenHeight div 6; |
411 topButtonBoundary := cScreenHeight div 6; |
402 |
412 |
|
413 setLength(fingers, 5); |
|
414 for finger in fingers do finger.id := -1; |
403 end; |
415 end; |
404 |
416 |
405 begin |
417 begin |
406 end. |
418 end. |