Remove FindSDL2 find-module, use sdl2-config.cmake instead
This requires SDL >= 2.0.4.
Since <https://bugzilla.libsdl.org/show_bug.cgi?id=2464> was fixed in
SDL 2.0.4, SDL behaves as a CMake "config-file package", even if it was
not itself built using CMake: it installs a sdl2-config.cmake file to
${libdir}/cmake/SDL2, which tells CMake where to find SDL's headers and
library, analogous to a pkg-config .pc file.
As a result, we no longer need to copy/paste a "find-module package"
to be able to find a system copy of SDL >= 2.0.4 with find_package(SDL2).
Find-module packages are now discouraged by the CMake developers, in
favour of having upstream projects behave as config-file packages.
This results in a small API change: FindSDL2 used to set SDL2_INCLUDE_DIR
and SDL2_LIBRARY, but the standard behaviour for config-file packages is
to set <name>_INCLUDE_DIRS and <name>_LIBRARIES. Use the CONFIG keyword
to make sure we search in config-file package mode, and will not find a
FindSDL2.cmake in some other directory that implements the old interface.
In addition to deleting redundant code, this avoids some assumptions in
FindSDL2 about the layout of a SDL installation. The current libsdl2-dev
package in Debian breaks those assumptions; this is considered a bug
and will hopefully be fixed soon, but it illustrates how fragile these
assumptions can be. We can be more robust against different installation
layouts by relying on SDL's own CMake integration.
When linking to a copy of CMake in a non-standard location, users can
now set the SDL2_DIR or CMAKE_PREFIX_PATH environment variable to point
to it; previously, these users would have used the SDL2DIR environment
variable. This continues to be unnecessary if using matching system-wide
installations of CMake and SDL2, for example both from Debian.
(*
* Hedgewars, a free turn based strategy game
* Copyright (c) 2012 Richard Deurwaarder <xeli@xelification.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*)
{$INCLUDE "options.inc"}
unit uTouch;
interface
uses SysUtils, uUtils, uConsole, uVariables, SDLh, uFloat, uConsts, uCommands, GLUnit, uTypes, uCaptions, uWorld, uGearsHedgehog;
procedure initModule;
procedure freeModule;
procedure ProcessTouch;
procedure NewTurnBeginning;
procedure onTouchDown(x, y: Single; pointerId: TSDL_FingerId);
procedure onTouchMotion(x, y, dx, dy: Single; pointerId: TSDL_FingerId);
procedure onTouchUp(x, y: Single; pointerId: TSDL_FingerId);
function convertToCursorX(x: LongInt): LongInt;
function convertToCursorY(y: LongInt): LongInt;
function addFinger(x,y: Longword; id: TSDL_FingerId): PTouch_Data;
function updateFinger(x,y,dx,dy: Longword; id: TSDL_FingerId): PTouch_Data;
procedure deleteFinger(id: TSDL_FingerId);
procedure onTouchClick(finger: TTouch_Data);
procedure onTouchDoubleClick(finger: TTouch_Data);
procedure onTouchLongClick(finger: TTouch_Data);
function findFinger(id: TSDL_FingerId): PTouch_Data;
procedure aim(finger: TTouch_Data);
function isOnCrosshair(finger: TTouch_Data): boolean;
function isOnCurrentHog(finger: TTouch_Data): boolean;
procedure convertToWorldCoord(var x,y: LongInt; finger: TTouch_Data);
procedure convertToFingerCoord(var x,y: LongInt; oldX, oldY: LongInt);
function fingerHasMoved(finger: TTouch_Data): boolean;
function calculateDelta(finger1, finger2: TTouch_Data): LongInt;
function getSecondFinger(finger: TTouch_Data): PTouch_Data;
function isOnRect(rect: TSDL_Rect; finger: TTouch_Data): boolean;
function isOnRect(x,y,w,h: LongInt; finger: TTouch_Data): boolean;
function isOnWidget(widget: TOnScreenWidget; finger: TTouch_Data): boolean;
procedure printFinger(finger: TTouch_Data);
implementation
const
clickTime = 200;
nilFingerId = High(TSDL_FingerId);
baseRectSize = 96;
var
rectSize, halfRectSize: LongInt;
pointerCount : Longword;
fingers: array of TTouch_Data;
moveCursor : boolean;
invertCursor : boolean;
//Pinch to zoom
pinchSize : LongInt;
baseZoomValue: GLFloat;
//aiming
aimingCrosshair: boolean;
aimingUp, aimingDown: boolean;
targetAngle: LongInt;
buttonsDown: Longword;
targetting, targetted: boolean; //true when targetting an airstrike or the like
procedure onTouchDown(x, y: Single; pointerId: TSDL_FingerId);
var
finger: PTouch_Data;
xr, yr, tmp: LongWord;
begin
xr:= round(x * cScreenWidth);
yr:= round(y * cScreenHeight);
finger:= addFinger(xr, yr, pointerId);
inc(buttonsDown);//inc buttonsDown, if we don't see a button down we'll dec it
if isOnCrosshair(finger^) then
begin
aimingCrosshair:= true;
aim(finger^);
moveCursor:= false;
exit;
end;
if isOnWidget(fireButton, finger^) then
begin
ParseTeamCommand('+attack');
moveCursor:= false;
finger^.pressedWidget:= @fireButton;
exit;
end;
if isOnWidget(arrowLeft, finger^) then
begin
ParseTeamCommand('+left');
moveCursor:= false;
finger^.pressedWidget:= @arrowLeft;
exit;
end;
if isOnWidget(arrowRight, finger^) then
begin
ParseTeamCommand('+right');
moveCursor:= false;
finger^.pressedWidget:= @arrowRight;
exit;
end;
if isOnWidget(arrowUp, finger^) then
begin
ParseTeamCommand('+up');
aimingUp:= true;
moveCursor:= false;
finger^.pressedWidget:= @arrowUp;
exit;
end;
if isOnWidget(arrowDown, finger^) then
begin
ParseTeamCommand('+down');
aimingDown:= true;
moveCursor:= false;
finger^.pressedWidget:= @arrowDown;
exit;
end;
if isOnWidget(pauseButton, finger^) then
begin
ParseTeamCommand('pause');
moveCursor:= false;
finger^.pressedWidget:= @pauseButton;
exit;
end;
if isOnWidget(utilityWidget, finger^) then
begin
finger^.pressedWidget:= @utilityWidget;
moveCursor:= false;
if(CurrentHedgehog <> nil) then
begin
if Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_Timerable <> 0 then
begin
tmp:= HHGetTimerMsg(CurrentHedgehog^.Gear);
if tmp <> MSGPARAM_INVALID then
ParseTeamCommand('/timer ' + inttostr(tmp mod 5 + 1));
end;
end;
exit;
end;
if isOnWidget(utilityWidget2, finger^) then
begin
finger^.pressedWidget:= @utilityWidget2;
moveCursor:= false;
if(CurrentHedgehog <> nil) then
begin
if Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_SetBounce <> 0 then
begin
tmp := HHGetBouncinessMsg(CurrentHedgehog^.Gear);
if tmp <> MSGPARAM_INVALID then
begin
ParseTeamCommand('+precise');
ParseTeamCommand('timer ' + inttostr(tmp mod 5 + 1));
bounceButtonPressed:= true;
end;
end;
end;
exit;
end;
dec(buttonsDown);//no buttonsDown, undo the inc() above
if buttonsDown = 0 then
begin
moveCursor:= true;
case pointerCount of
1:
targetting:= not(targetted) and (CurrentHedgehog <> nil) and (Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0);
2:
begin
moveCursor:= false;
pinchSize := calculateDelta(finger^, getSecondFinger(finger^)^);
baseZoomValue := ZoomValue
end;
end;
end;
end;
procedure onTouchMotion(x, y, dx, dy: Single; pointerId: TSDL_FingerId);
var
finger, secondFinger: PTouch_Data;
currentPinchDelta, zoom : Single;
xr, yr, dxr, dyr: LongWord;
begin
xr:= round(x * cScreenWidth);
yr:= round(y * cScreenHeight);
dxr:= round(dx * cScreenWidth);
dyr:= round(dy * cScreenHeight);
finger:= updateFinger(xr, yr, dxr, dyr, pointerId);
if finger = nil then
exit;
if moveCursor then
begin
if invertCursor then
begin
CursorPoint.X := CursorPoint.X - finger^.dx;
CursorPoint.Y := CursorPoint.Y + finger^.dy;
end
else
begin
CursorPoint.X := CursorPoint.X + finger^.dx;
CursorPoint.Y := CursorPoint.Y - finger^.dy;
end;
exit //todo change into switch rather than ugly ifs
end;
if aimingCrosshair then
begin
aim(finger^);
exit
end;
if (buttonsDown = 0) and (pointerCount = 2) then
begin
secondFinger := getSecondFinger(finger^);
currentPinchDelta := calculateDelta(finger^, secondFinger^) - pinchSize;
zoom := currentPinchDelta/cScreenWidth;
ZoomValue := baseZoomValue - (zoom * cMinMaxZoomLevelDelta);
if ZoomValue < cMaxZoomLevel then
ZoomValue := cMaxZoomLevel;
if ZoomValue > cMinZoomLevel then
ZoomValue := cMinZoomLevel;
end;
end;
procedure onTouchUp(x,y: Single; pointerId: TSDL_FingerId);
var
finger: PTouch_Data;
widget: POnScreenWidget;
xr, yr: LongWord;
begin
xr:= round(x * cScreenWidth);
yr:= round(y * cScreenHeight);
finger:= updateFinger(xr, yr, 0, 0, pointerId);
if finger = nil then
exit;
//Check for onTouchClick event
if not(fingerHasMoved(finger^)) then
begin
if (RealTicks - finger^.timeSinceDown) < clickTime then
onTouchClick(finger^)
else
onTouchLongClick(finger^);
end;
if aimingCrosshair then
begin
aimingCrosshair:= false;
ParseTeamCommand('-up');
ParseTeamCommand('-down');
dec(buttonsDown);
end;
widget:= finger^.pressedWidget;
if (buttonsDown > 0) and (widget <> nil) then
begin
dec(buttonsDown);
if widget = @arrowLeft then
ParseTeamCommand('-left');
if widget = @arrowRight then
ParseTeamCommand('-right');
if widget = @arrowUp then
ParseTeamCommand('-up');
if widget = @arrowDown then
ParseTeamCommand('-down');
if widget = @fireButton then
ParseTeamCommand('-attack');
if widget = @utilityWidget then
if (CurrentHedgehog <> nil)then
if(Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0)then
begin
ParseTeamCommand('put');
targetted:= true;
end
else if (CurAmmoGear <> nil) and (CurAmmoGear^.AmmoType = amSwitch) then
ParseTeamCommand('switch')
else WriteLnToConsole(inttostr(ord(Ammoz[CurrentHedgehog^.CurAmmoType].NameId)) + ' ' + inttostr(ord(sidSwitch)));
end;
if targetting then
AddCaption(trmsg[sidPressTarget], capcolDefault, capgrpAmmoInfo);
deleteFinger(pointerId);
end;
procedure onTouchDoubleClick(finger: TTouch_Data);
begin
finger := finger;//avoid compiler hint
end;
procedure onTouchLongClick(finger: TTouch_Data);
begin
if isOnWidget(jumpWidget, finger) then
begin
ParseTeamCommand('ljump');
exit;
end;
end;
procedure onTouchClick(finger: TTouch_Data);
begin
if bShowAmmoMenu then
begin
if isOnRect(AmmoRect, finger) then
begin
CursorPoint.X:= finger.x;
CursorPoint.Y:= finger.y;
ParseTeamCommand('put');
end
else
bShowAmmoMenu:= false;
exit;
end;
if isOnCurrentHog(finger) or isOnWidget(AMWidget, finger) then
begin
bShowAmmoMenu := true;
exit;
end;
if isOnWidget(jumpWidget, finger) then
begin
ParseTeamCommand('hjump');
exit;
end;
end;
function addFinger(x,y: Longword; id: TSDL_FingerId): PTouch_Data;
var
xCursor, yCursor, index : LongInt;
begin
// check array size
// note: pointerCount will be incremented later,
// so at this point it's the index of the new entry
if Length(fingers) <= pointerCount then
begin
setLength(fingers, Length(fingers)*2);
for index := Length(fingers) div 2 to (Length(fingers)-1) do
fingers[index].id := nilFingerId;
end;
xCursor := convertToCursorX(x);
yCursor := convertToCursorY(y);
//on removing fingers, all fingers are moved to the left
//with dynamic arrays being zero based, the new position of the finger is the old pointerCount
fingers[pointerCount].id := id;
fingers[pointerCount].historicalX := xCursor;
fingers[pointerCount].historicalY := yCursor;
fingers[pointerCount].x := xCursor;
fingers[pointerCount].y := yCursor;
fingers[pointerCount].dx := 0;
fingers[pointerCount].dy := 0;
fingers[pointerCount].timeSinceDown:= RealTicks;
fingers[pointerCount].pressedWidget:= nil;
addFinger:= @fingers[pointerCount];
inc(pointerCount);
end;
function updateFinger(x, y, dx, dy: Longword; id: TSDL_FingerId): PTouch_Data;
var finger : PTouch_Data;
begin
finger:= findFinger(id);
if finger <> nil then
begin
finger^.x:= convertToCursorX(x);
finger^.y:= convertToCursorY(y);
finger^.dx:= dx;
finger^.dy:= dy;
end
else
WriteLnToConsole('finger ' + inttostr(id) + ' not found');
updateFinger:= finger
end;
procedure deleteFinger(id: TSDL_FingerId);
var
index : Longword;
begin
dec(pointerCount);
for index := 0 to pointerCount do
begin
if fingers[index].id = id then
begin
//put the last finger into the spot of the finger to be removed,
//so that all fingers are packed to the far left
if pointerCount <> index then
begin
fingers[index].id := fingers[pointerCount].id;
fingers[index].x := fingers[pointerCount].x;
fingers[index].y := fingers[pointerCount].y;
fingers[index].historicalX := fingers[pointerCount].historicalX;
fingers[index].historicalY := fingers[pointerCount].historicalY;
fingers[index].timeSinceDown := fingers[pointerCount].timeSinceDown;
fingers[index].pressedWidget := fingers[pointerCount].pressedWidget;
fingers[pointerCount].id := nilFingerId;
end
else
fingers[index].id := nilFingerId;
break;
end;
end;
end;
procedure NewTurnBeginning;
begin
targetted:= false;
targetting:= false;
SetUtilityWidgetState(amNothing);
end;
procedure ProcessTouch;
var
deltaAngle: LongInt;
begin
invertCursor := not(bShowAmmoMenu or targetting);
if aimingCrosshair then
if CurrentHedgehog^.Gear <> nil then
begin
deltaAngle:= CurrentHedgehog^.Gear^.Angle - targetAngle;
if (deltaAngle > -5) and (deltaAngle < 5) then
begin
if(aimingUp)then
begin
aimingUp:= false;
ParseTeamCommand('-up');
end;
if(aimingDown)then
begin
aimingDown:= false;
ParseTeamCommand('-down');
end
end
else
begin
if (deltaAngle < 0) then
begin
if aimingUp then
begin
aimingUp:= false;
ParseTeamCommand('-up');
end;
if(aimingDown)then
begin
aimingDown:= true;
ParseTeamCommand('-down');
end
end
else
begin
if aimingDown then
begin
ParseTeamCommand('-down');
aimingDown:= false;
end;
if aimingUp then
begin
aimingUp:= true;
ParseTeamCommand('+up');
end;
end;
end;
end
else
begin
if aimingUp then
begin
ParseTeamCommand('-up');
aimingUp:= false;
end;
if aimingDown then
begin
ParseTeamCommand('-down');
aimingDown:= false;
end;
end;
if bounceButtonPressed then
begin
ParseTeamCommand('-precise');
bounceButtonPressed:= false;
end;
end;
function findFinger(id: TSDL_FingerId): PTouch_Data;
var
index: LongWord;
begin
for index:= 0 to (Length(fingers)-1) do
if fingers[index].id = id then
begin
findFinger:= @fingers[index];
exit;
end;
findFinger:= nil;
end;
procedure aim(finger: TTouch_Data);
var
hogX, hogY, touchX, touchY, deltaX, deltaY: LongInt;
begin
if CurrentHedgehog^.Gear <> nil then
begin
touchX := 0;//avoid compiler hint
touchY := 0;
hogX := hwRound(CurrentHedgehog^.Gear^.X);
hogY := hwRound(CurrentHedgehog^.Gear^.Y);
convertToWorldCoord(touchX, touchY, finger);
deltaX := abs(TouchX-HogX);
deltaY := TouchY-HogY;
targetAngle:= (Round(DeltaY / sqrt(sqr(deltaX) + sqr(deltaY)) * 2048) + 2048) div 2;
end; //if CurrentHedgehog^.Gear <> nil
end;
// These 4 convertToCursor functions convert xy coords from the SDL coordinate system to our CursorPoint coor system:
// - the SDL coordinate system is proportional to the screen and values are normalized in the onTouch* functions
// - the CursorPoint coordinate system goes from -cScreenWidth/2 to cScreenWidth/2 on the x axis
// and 0 to cScreenHeight on the x axis, (-cScreenWidth, cScreenHeight) being top left.
function convertToCursorX(x: LongInt): LongInt;
begin
convertToCursorX:= x - cScreenWidth shr 1;
end;
function convertToCursorY(y: LongInt): LongInt;
begin
convertToCursorY:= cScreenHeight - y;
end;
function isOnCrosshair(finger: TTouch_Data): boolean;
var
x, y: LongInt;
begin
x:= 0;
y:= 0;
convertToFingerCoord(x, y, CrosshairX, CrosshairY);
isOnCrosshair:= isOnRect(x - HalfRectSize, y - HalfRectSize, RectSize, RectSize, finger);
end;
function isOnCurrentHog(finger: TTouch_Data): boolean;
var
x, y: LongInt;
begin
x:= 0;
y:= 0;
convertToFingerCoord(x, y, hwRound(CurrentHedgehog^.Gear^.X), hwRound(CurrentHedgehog^.Gear^.Y));
isOnCurrentHog:= isOnRect(x - HalfRectSize, y - HalfRectSize, RectSize, RectSize, finger);
end;
procedure convertToFingerCoord(var x, y : LongInt; oldX, oldY: LongInt);
begin
x := oldX + WorldDx;
y := cScreenHeight - oldY - WorldDy;
end;
procedure convertToWorldCoord(var x,y: LongInt; finger: TTouch_Data);
begin
x := finger.x - WorldDx;
y := cScreenHeight - finger.y - WorldDy;
end;
//Method to calculate the distance this finger has moved since the downEvent
function fingerHasMoved(finger: TTouch_Data): boolean;
begin
fingerHasMoved := trunc(sqrt(sqr(finger.X-finger.historicalX) + sqr(finger.y-finger.historicalY))) > 30;
end;
function calculateDelta(finger1, finger2: TTouch_Data): LongInt; inline;
begin
calculateDelta := Round(sqrt(sqr(finger2.x-finger1.x) + sqr(finger2.y-finger1.y)));
end;
// Under the premise that all pointer ids in pointerIds:TSDL_FingerId are packed to the far left.
// If the pointer to be ignored is not pointerIds[0] the second must be there
function getSecondFinger(finger: TTouch_Data): PTouch_Data;
begin
if fingers[0].id = finger.id then
getSecondFinger := @fingers[1]
else
getSecondFinger := @fingers[0];
end;
function isOnRect(rect: TSDL_Rect; finger: TTouch_Data): boolean;
begin
isOnRect:= isOnRect(rect.x, rect.y, rect.w, rect.h, finger);
end;
function isOnRect(x,y,w,h: LongInt; finger: TTouch_Data): boolean;
begin
isOnRect:= (finger.x > x) and
(finger.x < x + w) and
(cScreenHeight - finger.y > y) and
(cScreenHeight - finger.y < y + h);
end;
function isOnWidget(widget: TOnScreenWidget; finger: TTouch_Data): boolean;
begin
isOnWidget:= widget.show and isOnRect(widget.active, finger);
end;
procedure printFinger(finger: TTouch_Data);
begin
WriteLnToConsole(Format('id: %d, x: %d y: %d (rel x: %d rel y: %d), time: %d',
[finger.id, finger.x, finger.y, finger.historicalX, finger.historicalY, finger.timeSinceDown]));
end;
procedure initModule;
var
index: Longword;
begin
buttonsDown:= 0;
pointerCount:= 0;
bounceButtonPressed:= false;
setLength(fingers, 4);
for index := 0 to (Length(fingers)-1) do
fingers[index].id := nilFingerId;
rectSize:= baseRectSize;
halfRectSize:= baseRectSize shr 1;
end;
procedure freeModule;
begin
end;
begin
end.