def _readMovementSettings(self, configDataSec):
     movementMappings = dict()
     movementMappings[getattr(
         Keys, configDataSec.readString('keyMoveLeft',
                                        'KEY_A'))] = Math.Vector3(-1, 0, 0)
     movementMappings[getattr(
         Keys, configDataSec.readString('keyMoveRight',
                                        'KEY_D'))] = Math.Vector3(1, 0, 0)
     movementMappings[getattr(
         Keys, configDataSec.readString('keyMoveForward',
                                        'KEY_W'))] = Math.Vector3(0, 0, 1)
     movementMappings[getattr(
         Keys, configDataSec.readString('keyMoveBackward',
                                        'KEY_S'))] = Math.Vector3(0, 0, -1)
     linearSensitivity = configDataSec.readFloat('linearVelocity', 40.0)
     self._movementSensor = KeySensor(movementMappings, linearSensitivity)
     self._verticalMovementSensor = KeySensor({}, linearSensitivity)
     self._movementSensor.currentVelocity = Math.Vector3()
Esempio n. 2
0
 def __readCfg(self, dataSec):
     if dataSec is None:
         LOG_WARNING('Invalid section <arcadeMode/camera> in avatar_input_handler.xml')
     self.__baseCfg = dict()
     bcfg = self.__baseCfg
     bcfg['keySensitivity'] = readFloat(dataSec, 'keySensitivity', 0, 10, 0.01)
     bcfg['sensitivity'] = readFloat(dataSec, 'sensitivity', 0, 10, 0.01)
     bcfg['scrollSensitivity'] = readFloat(dataSec, 'scrollSensitivity', 0, 10, 0.01)
     bcfg['angleRange'] = readVec2(dataSec, 'angleRange', (0, 0), (180, 180), (10, 110))
     bcfg['distRange'] = readVec2(dataSec, 'distRange', (1, 1), (100, 100), (2, 20))
     bcfg['angleRange'][0] = math.radians(bcfg['angleRange'][0]) - math.pi * 0.5
     bcfg['angleRange'][1] = math.radians(bcfg['angleRange'][1]) - math.pi * 0.5
     ds = Settings.g_instance.userPrefs[Settings.KEY_CONTROL_MODE]
     if ds is not None:
         ds = ds['arcadeMode/camera']
     self.__userCfg = dict()
     ucfg = self.__userCfg
     from account_helpers.SettingsCore import g_settingsCore
     ucfg['horzInvert'] = g_settingsCore.getSetting('mouseHorzInvert')
     ucfg['vertInvert'] = g_settingsCore.getSetting('mouseVertInvert')
     ucfg['keySensitivity'] = readFloat(ds, 'keySensitivity', 0.0, 10.0, 1.0)
     ucfg['sensitivity'] = readFloat(ds, 'sensitivity', 0.0, 10.0, 1.0)
     ucfg['scrollSensitivity'] = readFloat(ds, 'scrollSensitivity', 0.0, 10.0, 1.0)
     ucfg['startDist'] = readFloat(ds, 'startDist', 2, 500, 10)
     ucfg['startAngle'] = readFloat(ds, 'startAngle', 5, 180, 60)
     ucfg['startAngle'] = math.radians(ucfg['startAngle']) - math.pi * 0.5
     self.__cfg = dict()
     cfg = self.__cfg
     cfg['keySensitivity'] = bcfg['keySensitivity']
     cfg['sensitivity'] = bcfg['sensitivity']
     cfg['scrollSensitivity'] = bcfg['scrollSensitivity']
     cfg['angleRange'] = bcfg['angleRange']
     cfg['distRange'] = bcfg['distRange']
     cfg['horzInvert'] = ucfg['horzInvert']
     cfg['vertInvert'] = ucfg['vertInvert']
     cfg['keySensitivity'] *= ucfg['keySensitivity']
     cfg['sensitivity'] *= ucfg['sensitivity']
     cfg['scrollSensitivity'] *= ucfg['scrollSensitivity']
     cfg['startDist'] = ucfg['startDist']
     cfg['startAngle'] = ucfg['startAngle']
     enableShift = dataSec.readBool('shift', False)
     if enableShift:
         movementMappings = dict()
         movementMappings[Keys.KEY_A] = Math.Vector3(-1, 0, 0)
         movementMappings[Keys.KEY_D] = Math.Vector3(1, 0, 0)
         movementMappings[Keys.KEY_Q] = Math.Vector3(0, 1, 0)
         movementMappings[Keys.KEY_E] = Math.Vector3(0, -1, 0)
         movementMappings[Keys.KEY_W] = Math.Vector3(0, 0, 1)
         movementMappings[Keys.KEY_S] = Math.Vector3(0, 0, -1)
         shiftSensitivity = dataSec.readFloat('shiftSensitivity', 0.5)
         self.__shiftKeySensor = KeySensor(movementMappings, shiftSensitivity)
         self.__shiftKeySensor.reset(Math.Vector3())
     return
Esempio n. 3
0
class ArcadeCamera(ICamera):
    camera = property(lambda self: self.__cam)
    angles = property(lambda self: (self.__yaw, self.__pitch))

    def __init__(self, dataSec):
        self.__shiftKeySensor = None
        self.__readCfg(dataSec)
        self.__cam = BigWorld.CursorCamera()
        self.__camDist = 0
        self.__curSense = 0
        self.__curScrollSense = 0
        self.__pitch = 0.0
        self.__yaw = 0.0
        self.__cursorOffset = (0, 0)
        self.__postmortemMode = False
        self.__modelsToCollideWith = []
        self.__defaultPivotPos = Math.Vector3(0, 0, 0)
        self.__onChangeControlMode = None
        self.__autoUpdateCallbackId = None
        self.__cameraUpdateCallbackId = None
        return

    def create(self, pivotPos, onChangeControlMode=None, postmortemMode=False):
        self.__onChangeControlMode = onChangeControlMode
        self.__postmortemMode = postmortemMode
        replayCtrl = BattleReplay.g_replayCtrl
        vehicleID = replayCtrl.playerVehicleID if replayCtrl.isPlaying else BigWorld.player(
        ).playerVehicleID
        targetMat = BigWorld.entity(vehicleID).matrix
        self.__camDist = self.__cfg['startDist']
        self.__cam.pivotMaxDist = self.__camDist
        self.__cam.maxDistHalfLife = 0.0
        self.__cam.movementHalfLife = 0.0
        self.__cam.turningHalfLife = 0.0
        self.__cam.pivotPosition = self.__defaultPivotPos = pivotPos
        self.__pitch = self.__cfg['startAngle']
        self.__yaw = Math.Matrix(targetMat).yaw
        matrix = Math.Matrix()
        matrix.setRotateYPR(self.__updateAngles(0, 0))
        self.__cam.source = matrix

    def destroy(self):
        self.disable()
        self.__onChangeControlMode = None
        self.__cam = None
        self._writeUserPreferences()
        if self.__cameraUpdateCallbackId is not None:
            BigWorld.cancelCallback(self.__cameraUpdateCallbackId)
            self.__cameraUpdateCallbackId = None
        return

    def addModelsToCollideWith(self, models):
        self.__modelsToCollideWith = self.__modelsToCollideWith + models
        if BigWorld.camera() == self.__cam:
            self.__cam.wg_setModelsToCollideWith(self.__modelsToCollideWith)

    def removeModelsToCollideWith(self, models):
        for model in models:
            if self.__modelsToCollideWith.count(model) > 0:
                self.__modelsToCollideWith.remove(model)

        if BigWorld.camera() == self.__cam:
            self.__cam.wg_setModelsToCollideWith(self.__modelsToCollideWith)

    def focusOnPos(self, preferredPos):
        self.__calcStartAngles(self.__cam.target, preferredPos)

    def shiftCamPos(self, shift=None):
        matrixProduct = self.__cam.target
        shiftMat = getattr(matrixProduct, 'a', None)
        if shiftMat is None:
            return Math.Vector3()
        else:
            shiftMat = Math.Matrix(shiftMat)
            if shift is not None:
                camDirection = Math.Vector3(self.__cam.direction)
                camDirection.y = 0
                camDirection.normalise()
                normal = Math.Vector3(camDirection)
                normal.x = camDirection.z
                normal.z = -camDirection.x
                shiftMat.translation += camDirection * shift.z + Math.Vector3(
                    0, 1, 0) * shift.y + normal * shift.x
            else:
                shiftMat.setIdentity()
            matrixProduct.a = shiftMat
            return shiftMat.translation

    def enable(self,
               preferredPos=None,
               closesDist=False,
               postmortemParams=None):
        camSource = None
        camDist = None
        camTarget = BigWorld.player().getOwnVehicleMatrix()
        camTargetTransOnly = Math.WGTranslationOnlyMP()
        camTargetTransOnly.source = camTarget
        camTarget = Math.MatrixProduct()
        shift = Math.Matrix()
        shift.setIdentity()
        camTarget.a = shift
        camTarget.b = camTargetTransOnly
        if not self.__postmortemMode:
            if preferredPos is not None:
                self.__calcStartAngles(camTarget, preferredPos)
            if closesDist:
                camDist = self.__cfg['distRange'][0]
        elif postmortemParams is not None:
            self.__yaw = postmortemParams[0][0]
            self.__pitch = postmortemParams[0][1]
            camDist = postmortemParams[1]
            camSource = Math.Matrix()
            camSource.setRotateYPR((self.__yaw, self.__pitch, 0))
        else:
            camDist = self.__cfg['distRange'][1]
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying:
            camDist = None
            vehicle = BigWorld.entity(replayCtrl.playerVehicleID)
            if vehicle is not None:
                camTarget = vehicle.matrix
        if camDist is not None:
            self.__camDist = camDist
            self.__cam.pivotMaxDist = camDist
        if camSource is not None:
            self.__cam.source = camSource
        self.__cam.target = camTarget
        self.__cam.sptHiding = True
        self.__cam.wg_setModelsToCollideWith(self.__modelsToCollideWith)
        BigWorld.camera(self.__cam)
        self.__cameraUpdate()
        return

    def disable(self):
        self.__cam.wg_setModelsToCollideWith([])
        self.__cam.sptHiding = False
        BigWorld.camera(None)
        if self.__autoUpdateCallbackId is not None:
            BigWorld.cancelCallback(self.__autoUpdateCallbackId)
            self.__autoUpdateCallbackId = None
        if self.__cameraUpdateCallbackId is not None:
            BigWorld.cancelCallback(self.__cameraUpdateCallbackId)
            self.__cameraUpdateCallbackId = None
        if self.__shiftKeySensor is not None:
            self.__shiftKeySensor.reset(Math.Vector3())
        return

    def update(self, dx, dy, dz, rotateMode=True, zoomMode=True):
        self.__curSense = self.__cfg['sensitivity']
        self.__curScrollSense = self.__cfg['scrollSensitivity']
        self.__update(dx, dy, dz, rotateMode, zoomMode, False)

    def autoUpdate(self,
                   dx,
                   dy,
                   dz,
                   rotateMode=True,
                   zoomMode=True,
                   onlyOnce=False):
        self.__curSense = self.__cfg['keySensitivity']
        self.__curScrollSense = self.__cfg['keySensitivity']
        if self.__autoUpdateCallbackId is not None:
            BigWorld.cancelCallback(self.__autoUpdateCallbackId)
            self.__autoUpdateCallbackId = None
        if onlyOnce:
            self.__update(dx, dy, dz, rotateMode, zoomMode, False)
        else:
            self.__autoUpdateCallbackId = BigWorld.callback(
                0.001,
                partial(self.__update, dx, dy, dz, rotateMode, zoomMode, True))
        return

    def restoreDefaultsState(self):
        self.__camDist = self.__cfg['startDist']
        self.__cam.pivotMaxDist = self.__camDist
        self.__cam.maxDistHalfLife = 0.025
        self.__cam.movementHalfLife = 0.0
        self.__cam.turningHalfLife = 0.025
        self.__pitch = self.__cfg['startAngle']
        self.__yaw = Math.Matrix(self.__cam.target).yaw
        matrix = Math.Matrix()
        matrix.setRotateYPR(self.__updateAngles(0, 0))
        self.__cam.source = matrix

    def getUserConfigValue(self, name):
        return self.__userCfg.get(name)

    def setUserConfigValue(self, name, value):
        if name not in self.__userCfg:
            return
        self.__userCfg[name] = value
        if name not in ('keySensitivity', 'sensitivity', 'scrollSensitivity'):
            self.__cfg[name] = self.__userCfg[name]
        else:
            self.__cfg[name] = self.__baseCfg[name] * self.__userCfg[name]

    def cursorOffset(self, offset):
        self.__cursorOffset = offset

    def setPivotPosition(self, position):
        self.__cam.pivotPosition = self.__defaultPivotPos = position

    def getPivotPosition(self):
        return self.__defaultPivotPos

    def setCameraDistance(self, distance):
        distRange = self.__cfg['distRange']
        self.__camDist = distance
        self.__camDist = _clamp(distRange[0], distRange[1], self.__camDist)
        self.__cam.pivotMaxDist = self.__camDist

    def getCameraDistance(self):
        return self.__camDist

    def setYawPitch(self, yaw, pitch):
        anglesRange = self.__cfg['angleRange']
        self.__pitch = pitch
        self.__pitch = _clamp(anglesRange[0], anglesRange[1], self.__pitch)
        self.__yaw = yaw
        if self.__yaw > 2.0 * math.pi:
            self.__yaw -= 2.0 * math.pi
        elif self.__yaw < -2.0 * math.pi:
            self.__yaw += 2.0 * math.pi
        matrix = Math.Matrix()
        matrix.setRotateYPR((self.__yaw, self.__pitch, 0))
        self.__cam.source = matrix

    def getYawPitch(self):
        return (self.__yaw, self.__pitch)

    def getPivotPos(self):
        camPivotPos = self.__cam.pivotPosition
        posOnEntity = Math.Matrix(self.__cam.target).applyPoint(
            Math.Vector3(0, camPivotPos[1], 0))
        rotMat = Math.Matrix()
        rotMat.setRotateY(self.__yaw)
        pivotPos = posOnEntity + rotMat.applyPoint(
            Math.Vector3(camPivotPos[0], 0, camPivotPos[2]))
        return pivotPos

    def __calcStartAngles(self, targetMat, preferredPos):
        camDist = self.__camDist
        camPivotPos = self.__cam.pivotPosition
        posOnEntity = Math.Matrix(targetMat).applyPoint(
            Math.Vector3(0, camPivotPos[1], 0))
        yaw = (preferredPos - posOnEntity).yaw
        rotMat = Math.Matrix()
        rotMat.setRotateY(yaw)
        pivotPos = posOnEntity + rotMat.applyPoint(
            Math.Vector3(camPivotPos[0], 0, camPivotPos[2]))
        dir = preferredPos - pivotPos
        posDir = preferredPos - Math.Matrix(targetMat).applyToOrigin()
        pitch = -posDir.pitch
        try:
            pitch = self.__calcPitchAngle(camDist, dir)
            dist = self.__sceneCheck(yaw, pitch, pivotPos, camDist)
            if dist != 0:
                pitch = self.__calcPitchAngle(dist, dir)
        except:
            LOG_CURRENT_EXCEPTION()

        self.__pitch = pitch
        self.__yaw = yaw
        matrix = Math.Matrix()
        matrix.setRotateYPR(self.__updateAngles(0, 0))
        self.__cam.source = matrix

    def __getRotateAngle(self, vec2f):
        fov = BigWorld.projection().fov
        near = BigWorld.projection().nearPlane
        yLength = near * math.tan(fov * 0.5)
        return math.atan2(yLength * vec2f[1], near)

    def __sceneCheck(self, yaw, pitch, pivotPos, dist):
        dir = _vec3fFromYawPitch(yaw, -pitch)
        start = pivotPos - dir.scale(0.1)
        end = pivotPos - dir.scale(dist)
        colRes = BigWorld.wg_collideSegment(BigWorld.player().spaceID, start,
                                            end, 128)
        if colRes is not None:
            return Math.Vector3(colRes[0] - pivotPos).length
        else:
            return 0

    def __calcPitchAngle(self, camDist, dir):
        alpha = self.__getRotateAngle(self.__cursorOffset)
        a = camDist
        b = dir.length
        A = 2.0 * a * math.cos(alpha)
        B = a * a - b * b
        D = A * A - 4.0 * B
        if D > 0.0:
            c1 = (A + math.sqrt(D)) * 0.5
            c2 = (A - math.sqrt(D)) * 0.5
            c = c1 if c1 > c2 else c2
            beta = math.acos((a * a + b * b - c * c) / (2.0 * a * b))
            eta = math.pi - beta
            return -dir.pitch - eta
        else:
            return -dir.pitch

    def __readCfg(self, dataSec):
        if dataSec is None:
            LOG_WARNING(
                'Invalid section <arcadeMode/camera> in avatar_input_handler.xml'
            )
        self.__baseCfg = dict()
        bcfg = self.__baseCfg
        bcfg['keySensitivity'] = readFloat(dataSec, 'keySensitivity', 0, 10,
                                           0.01)
        bcfg['sensitivity'] = readFloat(dataSec, 'sensitivity', 0, 10, 0.01)
        bcfg['scrollSensitivity'] = readFloat(dataSec, 'scrollSensitivity', 0,
                                              10, 0.01)
        bcfg['angleRange'] = readVec2(dataSec, 'angleRange', (0, 0),
                                      (180, 180), (10, 110))
        bcfg['distRange'] = readVec2(dataSec, 'distRange', (1, 1), (100, 100),
                                     (2, 20))
        bcfg['angleRange'][0] = math.radians(
            bcfg['angleRange'][0]) - math.pi * 0.5
        bcfg['angleRange'][1] = math.radians(
            bcfg['angleRange'][1]) - math.pi * 0.5
        ds = Settings.g_instance.userPrefs[Settings.KEY_CONTROL_MODE]
        if ds is not None:
            ds = ds['arcadeMode/camera']
        self.__userCfg = dict()
        ucfg = self.__userCfg
        from account_helpers.SettingsCore import g_settingsCore
        ucfg['horzInvert'] = g_settingsCore.getSetting('mouseHorzInvert')
        ucfg['vertInvert'] = g_settingsCore.getSetting('mouseVertInvert')
        ucfg['keySensitivity'] = readFloat(ds, 'keySensitivity', 0.0, 10.0,
                                           1.0)
        ucfg['sensitivity'] = readFloat(ds, 'sensitivity', 0.0, 10.0, 1.0)
        ucfg['scrollSensitivity'] = readFloat(ds, 'scrollSensitivity', 0.0,
                                              10.0, 1.0)
        ucfg['startDist'] = readFloat(ds, 'startDist', 2, 500, 10)
        ucfg['startAngle'] = readFloat(ds, 'startAngle', 5, 180, 60)
        ucfg['startAngle'] = math.radians(ucfg['startAngle']) - math.pi * 0.5
        self.__cfg = dict()
        cfg = self.__cfg
        cfg['keySensitivity'] = bcfg['keySensitivity']
        cfg['sensitivity'] = bcfg['sensitivity']
        cfg['scrollSensitivity'] = bcfg['scrollSensitivity']
        cfg['angleRange'] = bcfg['angleRange']
        cfg['distRange'] = bcfg['distRange']
        cfg['horzInvert'] = ucfg['horzInvert']
        cfg['vertInvert'] = ucfg['vertInvert']
        cfg['keySensitivity'] *= ucfg['keySensitivity']
        cfg['sensitivity'] *= ucfg['sensitivity']
        cfg['scrollSensitivity'] *= ucfg['scrollSensitivity']
        cfg['startDist'] = ucfg['startDist']
        cfg['startAngle'] = ucfg['startAngle']
        enableShift = dataSec.readBool('shift', False)
        if enableShift:
            movementMappings = dict()
            movementMappings[Keys.KEY_A] = Math.Vector3(-1, 0, 0)
            movementMappings[Keys.KEY_D] = Math.Vector3(1, 0, 0)
            movementMappings[Keys.KEY_Q] = Math.Vector3(0, 1, 0)
            movementMappings[Keys.KEY_E] = Math.Vector3(0, -1, 0)
            movementMappings[Keys.KEY_W] = Math.Vector3(0, 0, 1)
            movementMappings[Keys.KEY_S] = Math.Vector3(0, 0, -1)
            shiftSensitivity = dataSec.readFloat('shiftSensitivity', 0.5)
            self.__shiftKeySensor = KeySensor(movementMappings,
                                              shiftSensitivity)
            self.__shiftKeySensor.reset(Math.Vector3())
        return

    def _writeUserPreferences(self):
        ds = Settings.g_instance.userPrefs
        if not ds.has_key(Settings.KEY_CONTROL_MODE):
            ds.write(Settings.KEY_CONTROL_MODE, '')
        ucfg = self.__userCfg
        ds = ds[Settings.KEY_CONTROL_MODE]
        ds.writeBool('arcadeMode/camera/horzInvert', ucfg['horzInvert'])
        ds.writeBool('arcadeMode/camera/vertInvert', ucfg['vertInvert'])
        ds.writeFloat('arcadeMode/camera/keySensitivity',
                      ucfg['keySensitivity'])
        ds.writeFloat('arcadeMode/camera/sensitivity', ucfg['sensitivity'])
        ds.writeFloat('arcadeMode/camera/scrollSensitivity',
                      ucfg['scrollSensitivity'])
        ds.writeFloat('arcadeMode/camera/startDist', ucfg['startDist'])
        ucfg['startAngle'] = math.degrees(ucfg['startAngle'] + math.pi * 0.5)
        ds.writeFloat('arcadeMode/camera/startAngle', ucfg['startAngle'])

    def calcYawPitchDelta(self, dx, dy):
        return (dx * self.__curSense * (-1 if self.__cfg['horzInvert'] else 1),
                dy * self.__curSense * (-1 if self.__cfg['vertInvert'] else 1))

    def __updateAngles(self, dx, dy):
        cfg = self.__cfg
        anglesRange = cfg['angleRange']
        offset = 0
        yawDelta, pitchDelta = self.calcYawPitchDelta(dx, dy)
        self.__pitch -= pitchDelta
        self.__pitch = _clamp(anglesRange[0] + offset, anglesRange[1] + offset,
                              self.__pitch)
        self.__yaw += yawDelta
        if self.__yaw > 2.0 * math.pi:
            self.__yaw -= 2.0 * math.pi
        elif self.__yaw < -2.0 * math.pi:
            self.__yaw += 2.0 * math.pi
        return (self.__yaw, self.__pitch, 0)

    def __update(self,
                 dx,
                 dy,
                 dz,
                 rotateMode=True,
                 zoomMode=True,
                 isCallback=False):
        if isCallback:
            self.__autoUpdateCallbackId = BigWorld.callback(
                0.001,
                partial(self.__update, dx, dy, dz, rotateMode, zoomMode, True))
        cfg = self.__cfg
        if zoomMode and dz != 0:
            distRange = cfg['distRange']
            prevCam = self.__camDist
            self.__camDist -= dz * float(self.__curScrollSense)
            self.__camDist = _clamp(distRange[0], distRange[1], self.__camDist)
            self.__userCfg['startDist'] = self.__camDist
            if prevCam == self.__camDist and self.__onChangeControlMode is not None:
                if _almostZero(self.__camDist - distRange[0]):
                    self.__onChangeControlMode()
            self.__cam.pivotMaxDist = self.__camDist
        if rotateMode:
            matrix = Math.Matrix()
            matrix.setRotateYPR(self.__updateAngles(dx, dy))
            self.__cam.source = matrix
        return

    def __cameraUpdate(self):
        self.__cameraUpdateCallbackId = BigWorld.callback(
            0.0, self.__cameraUpdate)
        if self.__cam.target is None:
            self.__cam.pivotPosition = self.__defaultPivotPos
            return
        else:
            if self.__shiftKeySensor is not None:
                self.__shiftKeySensor.update(1.0)
                if self.__shiftKeySensor.currentVelocity.lengthSquared > 0.0:
                    currentShift = self.shiftCamPos(
                        self.__shiftKeySensor.currentVelocity)
                    self.__shiftKeySensor.currentVelocity = Math.Vector3()
                    if currentShift.lengthSquared > 0.01:
                        return
            targetPosition = Math.Matrix(self.__cam.target).translation
            BOTTOM_SHIFT = Math.Vector3(0, 2.0, 0)
            collData = BigWorld.wg_collideSegment(
                BigWorld.player().spaceID, targetPosition + BOTTOM_SHIFT,
                targetPosition + Math.Vector3(0, self.__defaultPivotPos.y, 0),
                7)
            if collData is not None:
                collPoint = collData[0]
                collNormal = collData[1]
                if collNormal.dot(Math.Vector3(0, -1, 0)) > 0:
                    self.__cam.pivotPosition = collPoint - Math.Vector3(
                        0, 0.3, 0) - targetPosition
            else:
                self.__cam.pivotPosition = self.__defaultPivotPos
            return

    def handleKeyEvent(self, isDown, key, mods, event=None):
        if self.__shiftKeySensor is None:
            return False
        elif BigWorld.isKeyDown(Keys.KEY_CAPSLOCK) and mods & 4:
            if key == Keys.KEY_C:
                self.shiftCamPos()
            return self.__shiftKeySensor.handleKeyEvent(key, isDown)
        else:
            self.__shiftKeySensor.reset(Math.Vector3())
            return False
Esempio n. 4
0
 def __readCfg(self, dataSec):
     if dataSec is None:
         LOG_WARNING(
             'Invalid section <arcadeMode/camera> in avatar_input_handler.xml'
         )
     self.__baseCfg = dict()
     bcfg = self.__baseCfg
     bcfg['keySensitivity'] = readFloat(dataSec, 'keySensitivity', 0, 10,
                                        0.01)
     bcfg['sensitivity'] = readFloat(dataSec, 'sensitivity', 0, 10, 0.01)
     bcfg['scrollSensitivity'] = readFloat(dataSec, 'scrollSensitivity', 0,
                                           10, 0.01)
     bcfg['angleRange'] = readVec2(dataSec, 'angleRange', (0, 0),
                                   (180, 180), (10, 110))
     bcfg['distRange'] = readVec2(dataSec, 'distRange', (1, 1), (100, 100),
                                  (2, 20))
     bcfg['angleRange'][0] = math.radians(
         bcfg['angleRange'][0]) - math.pi * 0.5
     bcfg['angleRange'][1] = math.radians(
         bcfg['angleRange'][1]) - math.pi * 0.5
     ds = Settings.g_instance.userPrefs[Settings.KEY_CONTROL_MODE]
     if ds is not None:
         ds = ds['arcadeMode/camera']
     self.__userCfg = dict()
     ucfg = self.__userCfg
     from account_helpers.SettingsCore import g_settingsCore
     ucfg['horzInvert'] = g_settingsCore.getSetting('mouseHorzInvert')
     ucfg['vertInvert'] = g_settingsCore.getSetting('mouseVertInvert')
     ucfg['keySensitivity'] = readFloat(ds, 'keySensitivity', 0.0, 10.0,
                                        1.0)
     ucfg['sensitivity'] = readFloat(ds, 'sensitivity', 0.0, 10.0, 1.0)
     ucfg['scrollSensitivity'] = readFloat(ds, 'scrollSensitivity', 0.0,
                                           10.0, 1.0)
     ucfg['startDist'] = readFloat(ds, 'startDist', 2, 500, 10)
     ucfg['startAngle'] = readFloat(ds, 'startAngle', 5, 180, 60)
     ucfg['startAngle'] = math.radians(ucfg['startAngle']) - math.pi * 0.5
     self.__cfg = dict()
     cfg = self.__cfg
     cfg['keySensitivity'] = bcfg['keySensitivity']
     cfg['sensitivity'] = bcfg['sensitivity']
     cfg['scrollSensitivity'] = bcfg['scrollSensitivity']
     cfg['angleRange'] = bcfg['angleRange']
     cfg['distRange'] = bcfg['distRange']
     cfg['horzInvert'] = ucfg['horzInvert']
     cfg['vertInvert'] = ucfg['vertInvert']
     cfg['keySensitivity'] *= ucfg['keySensitivity']
     cfg['sensitivity'] *= ucfg['sensitivity']
     cfg['scrollSensitivity'] *= ucfg['scrollSensitivity']
     cfg['startDist'] = ucfg['startDist']
     cfg['startAngle'] = ucfg['startAngle']
     enableShift = dataSec.readBool('shift', False)
     if enableShift:
         movementMappings = dict()
         movementMappings[Keys.KEY_A] = Math.Vector3(-1, 0, 0)
         movementMappings[Keys.KEY_D] = Math.Vector3(1, 0, 0)
         movementMappings[Keys.KEY_Q] = Math.Vector3(0, 1, 0)
         movementMappings[Keys.KEY_E] = Math.Vector3(0, -1, 0)
         movementMappings[Keys.KEY_W] = Math.Vector3(0, 0, 1)
         movementMappings[Keys.KEY_S] = Math.Vector3(0, 0, -1)
         shiftSensitivity = dataSec.readFloat('shiftSensitivity', 0.5)
         self.__shiftKeySensor = KeySensor(movementMappings,
                                           shiftSensitivity)
         self.__shiftKeySensor.reset(Math.Vector3())
     return
 def _readRotationSettings(self, configDataSec, rotationMappings):
     rotationSensitivity = configDataSec.readFloat('angularVelocity', 0.7)
     self._rotationSensor = KeySensor(rotationMappings, rotationSensitivity)
     self._rotationSensor.currentVelocity = Math.Vector3()
Esempio n. 6
0
class ArcadeCamera(ICamera):
    camera = property(lambda self: self.__cam)
    angles = property(lambda self: (self.__yaw, self.__pitch))

    def __init__(self, dataSec):
        self.__shiftKeySensor = None
        self.__readCfg(dataSec)
        self.__cam = BigWorld.CursorCamera()
        self.__camDist = 0
        self.__curSense = 0
        self.__curScrollSense = 0
        self.__pitch = 0.0
        self.__yaw = 0.0
        self.__cursorOffset = (0, 0)
        self.__postmortemMode = False
        self.__modelsToCollideWith = []
        self.__defaultPivotPos = Math.Vector3(0, 0, 0)
        self.__onChangeControlMode = None
        self.__autoUpdateCallbackId = None
        self.__cameraUpdateCallbackId = None
        return

    def create(self, pivotPos, onChangeControlMode = None, postmortemMode = False):
        self.__onChangeControlMode = onChangeControlMode
        self.__postmortemMode = postmortemMode
        replayCtrl = BattleReplay.g_replayCtrl
        vehicleID = replayCtrl.playerVehicleID if replayCtrl.isPlaying else BigWorld.player().playerVehicleID
        targetMat = BigWorld.entity(vehicleID).matrix
        self.__camDist = self.__cfg['startDist']
        self.__cam.pivotMaxDist = self.__camDist
        self.__cam.maxDistHalfLife = 0.0
        self.__cam.movementHalfLife = 0.0
        self.__cam.turningHalfLife = 0.0
        self.__cam.pivotPosition = self.__defaultPivotPos = pivotPos
        self.__pitch = self.__cfg['startAngle']
        self.__yaw = Math.Matrix(targetMat).yaw
        matrix = Math.Matrix()
        matrix.setRotateYPR(self.__updateAngles(0, 0))
        self.__cam.source = matrix

    def destroy(self):
        self.disable()
        self.__onChangeControlMode = None
        self.__cam = None
        self._writeUserPreferences()
        if self.__cameraUpdateCallbackId is not None:
            BigWorld.cancelCallback(self.__cameraUpdateCallbackId)
            self.__cameraUpdateCallbackId = None
        return

    def addModelsToCollideWith(self, models):
        self.__modelsToCollideWith = self.__modelsToCollideWith + models
        if BigWorld.camera() == self.__cam:
            self.__cam.wg_setModelsToCollideWith(self.__modelsToCollideWith)

    def removeModelsToCollideWith(self, models):
        for model in models:
            if self.__modelsToCollideWith.count(model) > 0:
                self.__modelsToCollideWith.remove(model)

        if BigWorld.camera() == self.__cam:
            self.__cam.wg_setModelsToCollideWith(self.__modelsToCollideWith)

    def focusOnPos(self, preferredPos):
        self.__calcStartAngles(self.__cam.target, preferredPos)

    def shiftCamPos(self, shift = None):
        matrixProduct = self.__cam.target
        shiftMat = getattr(matrixProduct, 'a', None)
        if shiftMat is None:
            return Math.Vector3()
        else:
            shiftMat = Math.Matrix(shiftMat)
            if shift is not None:
                camDirection = Math.Vector3(self.__cam.direction)
                camDirection.y = 0
                camDirection.normalise()
                normal = Math.Vector3(camDirection)
                normal.x = camDirection.z
                normal.z = -camDirection.x
                shiftMat.translation += camDirection * shift.z + Math.Vector3(0, 1, 0) * shift.y + normal * shift.x
            else:
                shiftMat.setIdentity()
            matrixProduct.a = shiftMat
            return shiftMat.translation

    def enable(self, preferredPos = None, closesDist = False, postmortemParams = None):
        camSource = None
        camDist = None
        camTarget = BigWorld.player().getOwnVehicleMatrix()
        camTargetTransOnly = Math.WGTranslationOnlyMP()
        camTargetTransOnly.source = camTarget
        camTarget = Math.MatrixProduct()
        shift = Math.Matrix()
        shift.setIdentity()
        camTarget.a = shift
        camTarget.b = camTargetTransOnly
        if not self.__postmortemMode:
            if preferredPos is not None:
                self.__calcStartAngles(camTarget, preferredPos)
            if closesDist:
                camDist = self.__cfg['distRange'][0]
        elif postmortemParams is not None:
            self.__yaw = postmortemParams[0][0]
            self.__pitch = postmortemParams[0][1]
            camDist = postmortemParams[1]
            camSource = Math.Matrix()
            camSource.setRotateYPR((self.__yaw, self.__pitch, 0))
        else:
            camDist = self.__cfg['distRange'][1]
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying:
            camDist = None
            vehicle = BigWorld.entity(replayCtrl.playerVehicleID)
            if vehicle is not None:
                camTarget = vehicle.matrix
        if camDist is not None:
            self.__camDist = camDist
            self.__cam.pivotMaxDist = camDist
        if camSource is not None:
            self.__cam.source = camSource
        self.__cam.target = camTarget
        self.__cam.sptHiding = True
        self.__cam.wg_setModelsToCollideWith(self.__modelsToCollideWith)
        BigWorld.camera(self.__cam)
        self.__cameraUpdate()
        return

    def disable(self):
        self.__cam.wg_setModelsToCollideWith([])
        self.__cam.sptHiding = False
        BigWorld.camera(None)
        if self.__autoUpdateCallbackId is not None:
            BigWorld.cancelCallback(self.__autoUpdateCallbackId)
            self.__autoUpdateCallbackId = None
        if self.__cameraUpdateCallbackId is not None:
            BigWorld.cancelCallback(self.__cameraUpdateCallbackId)
            self.__cameraUpdateCallbackId = None
        if self.__shiftKeySensor is not None:
            self.__shiftKeySensor.reset(Math.Vector3())
        return

    def update(self, dx, dy, dz, rotateMode = True, zoomMode = True):
        self.__curSense = self.__cfg['sensitivity']
        self.__curScrollSense = self.__cfg['scrollSensitivity']
        self.__update(dx, dy, dz, rotateMode, zoomMode, False)

    def autoUpdate(self, dx, dy, dz, rotateMode = True, zoomMode = True, onlyOnce = False):
        self.__curSense = self.__cfg['keySensitivity']
        self.__curScrollSense = self.__cfg['keySensitivity']
        if self.__autoUpdateCallbackId is not None:
            BigWorld.cancelCallback(self.__autoUpdateCallbackId)
            self.__autoUpdateCallbackId = None
        if onlyOnce:
            self.__update(dx, dy, dz, rotateMode, zoomMode, False)
        else:
            self.__autoUpdateCallbackId = BigWorld.callback(0.001, partial(self.__update, dx, dy, dz, rotateMode, zoomMode, True))
        return

    def restoreDefaultsState(self):
        self.__camDist = self.__cfg['startDist']
        self.__cam.pivotMaxDist = self.__camDist
        self.__cam.maxDistHalfLife = 0.025
        self.__cam.movementHalfLife = 0.0
        self.__cam.turningHalfLife = 0.025
        self.__pitch = self.__cfg['startAngle']
        self.__yaw = Math.Matrix(self.__cam.target).yaw
        matrix = Math.Matrix()
        matrix.setRotateYPR(self.__updateAngles(0, 0))
        self.__cam.source = matrix

    def getUserConfigValue(self, name):
        return self.__userCfg.get(name)

    def setUserConfigValue(self, name, value):
        if name not in self.__userCfg:
            return
        self.__userCfg[name] = value
        if name not in ('keySensitivity', 'sensitivity', 'scrollSensitivity'):
            self.__cfg[name] = self.__userCfg[name]
        else:
            self.__cfg[name] = self.__baseCfg[name] * self.__userCfg[name]

    def cursorOffset(self, offset):
        self.__cursorOffset = offset

    def setPivotPosition(self, position):
        self.__cam.pivotPosition = self.__defaultPivotPos = position

    def getPivotPosition(self):
        return self.__defaultPivotPos

    def setCameraDistance(self, distance):
        distRange = self.__cfg['distRange']
        self.__camDist = distance
        self.__camDist = _clamp(distRange[0], distRange[1], self.__camDist)
        self.__cam.pivotMaxDist = self.__camDist

    def getCameraDistance(self):
        return self.__camDist

    def setYawPitch(self, yaw, pitch):
        anglesRange = self.__cfg['angleRange']
        self.__pitch = pitch
        self.__pitch = _clamp(anglesRange[0], anglesRange[1], self.__pitch)
        self.__yaw = yaw
        if self.__yaw > 2.0 * math.pi:
            self.__yaw -= 2.0 * math.pi
        elif self.__yaw < -2.0 * math.pi:
            self.__yaw += 2.0 * math.pi
        matrix = Math.Matrix()
        matrix.setRotateYPR((self.__yaw, self.__pitch, 0))
        self.__cam.source = matrix

    def getYawPitch(self):
        return (self.__yaw, self.__pitch)

    def getPivotPos(self):
        camPivotPos = self.__cam.pivotPosition
        posOnEntity = Math.Matrix(self.__cam.target).applyPoint(Math.Vector3(0, camPivotPos[1], 0))
        rotMat = Math.Matrix()
        rotMat.setRotateY(self.__yaw)
        pivotPos = posOnEntity + rotMat.applyPoint(Math.Vector3(camPivotPos[0], 0, camPivotPos[2]))
        return pivotPos

    def __calcStartAngles(self, targetMat, preferredPos):
        camDist = self.__camDist
        camPivotPos = self.__cam.pivotPosition
        posOnEntity = Math.Matrix(targetMat).applyPoint(Math.Vector3(0, camPivotPos[1], 0))
        yaw = (preferredPos - posOnEntity).yaw
        rotMat = Math.Matrix()
        rotMat.setRotateY(yaw)
        pivotPos = posOnEntity + rotMat.applyPoint(Math.Vector3(camPivotPos[0], 0, camPivotPos[2]))
        dir = preferredPos - pivotPos
        posDir = preferredPos - Math.Matrix(targetMat).applyToOrigin()
        pitch = -posDir.pitch
        try:
            pitch = self.__calcPitchAngle(camDist, dir)
            dist = self.__sceneCheck(yaw, pitch, pivotPos, camDist)
            if dist != 0:
                pitch = self.__calcPitchAngle(dist, dir)
        except:
            LOG_CURRENT_EXCEPTION()

        self.__pitch = pitch
        self.__yaw = yaw
        matrix = Math.Matrix()
        matrix.setRotateYPR(self.__updateAngles(0, 0))
        self.__cam.source = matrix

    def __getRotateAngle(self, vec2f):
        fov = BigWorld.projection().fov
        near = BigWorld.projection().nearPlane
        yLength = near * math.tan(fov * 0.5)
        return math.atan2(yLength * vec2f[1], near)

    def __sceneCheck(self, yaw, pitch, pivotPos, dist):
        dir = _vec3fFromYawPitch(yaw, -pitch)
        start = pivotPos - dir.scale(0.1)
        end = pivotPos - dir.scale(dist)
        colRes = BigWorld.wg_collideSegment(BigWorld.player().spaceID, start, end, 128)
        if colRes is not None:
            return Math.Vector3(colRes[0] - pivotPos).length
        else:
            return 0

    def __calcPitchAngle(self, camDist, dir):
        alpha = self.__getRotateAngle(self.__cursorOffset)
        a = camDist
        b = dir.length
        A = 2.0 * a * math.cos(alpha)
        B = a * a - b * b
        D = A * A - 4.0 * B
        if D > 0.0:
            c1 = (A + math.sqrt(D)) * 0.5
            c2 = (A - math.sqrt(D)) * 0.5
            c = c1 if c1 > c2 else c2
            beta = math.acos((a * a + b * b - c * c) / (2.0 * a * b))
            eta = math.pi - beta
            return -dir.pitch - eta
        else:
            return -dir.pitch

    def __readCfg(self, dataSec):
        if dataSec is None:
            LOG_WARNING('Invalid section <arcadeMode/camera> in avatar_input_handler.xml')
        self.__baseCfg = dict()
        bcfg = self.__baseCfg
        bcfg['keySensitivity'] = readFloat(dataSec, 'keySensitivity', 0, 10, 0.01)
        bcfg['sensitivity'] = readFloat(dataSec, 'sensitivity', 0, 10, 0.01)
        bcfg['scrollSensitivity'] = readFloat(dataSec, 'scrollSensitivity', 0, 10, 0.01)
        bcfg['angleRange'] = readVec2(dataSec, 'angleRange', (0, 0), (180, 180), (10, 110))
        bcfg['distRange'] = readVec2(dataSec, 'distRange', (1, 1), (100, 100), (2, 20))
        bcfg['angleRange'][0] = math.radians(bcfg['angleRange'][0]) - math.pi * 0.5
        bcfg['angleRange'][1] = math.radians(bcfg['angleRange'][1]) - math.pi * 0.5
        ds = Settings.g_instance.userPrefs[Settings.KEY_CONTROL_MODE]
        if ds is not None:
            ds = ds['arcadeMode/camera']
        self.__userCfg = dict()
        ucfg = self.__userCfg
        from account_helpers.SettingsCore import g_settingsCore
        ucfg['horzInvert'] = g_settingsCore.getSetting('mouseHorzInvert')
        ucfg['vertInvert'] = g_settingsCore.getSetting('mouseVertInvert')
        ucfg['keySensitivity'] = readFloat(ds, 'keySensitivity', 0.0, 10.0, 1.0)
        ucfg['sensitivity'] = readFloat(ds, 'sensitivity', 0.0, 10.0, 1.0)
        ucfg['scrollSensitivity'] = readFloat(ds, 'scrollSensitivity', 0.0, 10.0, 1.0)
        ucfg['startDist'] = readFloat(ds, 'startDist', 2, 500, 10)
        ucfg['startAngle'] = readFloat(ds, 'startAngle', 5, 180, 60)
        ucfg['startAngle'] = math.radians(ucfg['startAngle']) - math.pi * 0.5
        self.__cfg = dict()
        cfg = self.__cfg
        cfg['keySensitivity'] = bcfg['keySensitivity']
        cfg['sensitivity'] = bcfg['sensitivity']
        cfg['scrollSensitivity'] = bcfg['scrollSensitivity']
        cfg['angleRange'] = bcfg['angleRange']
        cfg['distRange'] = bcfg['distRange']
        cfg['horzInvert'] = ucfg['horzInvert']
        cfg['vertInvert'] = ucfg['vertInvert']
        cfg['keySensitivity'] *= ucfg['keySensitivity']
        cfg['sensitivity'] *= ucfg['sensitivity']
        cfg['scrollSensitivity'] *= ucfg['scrollSensitivity']
        cfg['startDist'] = ucfg['startDist']
        cfg['startAngle'] = ucfg['startAngle']
        enableShift = dataSec.readBool('shift', False)
        if enableShift:
            movementMappings = dict()
            movementMappings[Keys.KEY_A] = Math.Vector3(-1, 0, 0)
            movementMappings[Keys.KEY_D] = Math.Vector3(1, 0, 0)
            movementMappings[Keys.KEY_Q] = Math.Vector3(0, 1, 0)
            movementMappings[Keys.KEY_E] = Math.Vector3(0, -1, 0)
            movementMappings[Keys.KEY_W] = Math.Vector3(0, 0, 1)
            movementMappings[Keys.KEY_S] = Math.Vector3(0, 0, -1)
            shiftSensitivity = dataSec.readFloat('shiftSensitivity', 0.5)
            self.__shiftKeySensor = KeySensor(movementMappings, shiftSensitivity)
            self.__shiftKeySensor.reset(Math.Vector3())
        return

    def _writeUserPreferences(self):
        ds = Settings.g_instance.userPrefs
        if not ds.has_key(Settings.KEY_CONTROL_MODE):
            ds.write(Settings.KEY_CONTROL_MODE, '')
        ucfg = self.__userCfg
        ds = ds[Settings.KEY_CONTROL_MODE]
        ds.writeBool('arcadeMode/camera/horzInvert', ucfg['horzInvert'])
        ds.writeBool('arcadeMode/camera/vertInvert', ucfg['vertInvert'])
        ds.writeFloat('arcadeMode/camera/keySensitivity', ucfg['keySensitivity'])
        ds.writeFloat('arcadeMode/camera/sensitivity', ucfg['sensitivity'])
        ds.writeFloat('arcadeMode/camera/scrollSensitivity', ucfg['scrollSensitivity'])
        ds.writeFloat('arcadeMode/camera/startDist', ucfg['startDist'])
        ucfg['startAngle'] = math.degrees(ucfg['startAngle'] + math.pi * 0.5)
        ds.writeFloat('arcadeMode/camera/startAngle', ucfg['startAngle'])

    def calcYawPitchDelta(self, dx, dy):
        return (dx * self.__curSense * (-1 if self.__cfg['horzInvert'] else 1), dy * self.__curSense * (-1 if self.__cfg['vertInvert'] else 1))

    def __updateAngles(self, dx, dy):
        cfg = self.__cfg
        anglesRange = cfg['angleRange']
        offset = 0
        yawDelta, pitchDelta = self.calcYawPitchDelta(dx, dy)
        self.__pitch -= pitchDelta
        self.__pitch = _clamp(anglesRange[0] + offset, anglesRange[1] + offset, self.__pitch)
        self.__yaw += yawDelta
        if self.__yaw > 2.0 * math.pi:
            self.__yaw -= 2.0 * math.pi
        elif self.__yaw < -2.0 * math.pi:
            self.__yaw += 2.0 * math.pi
        return (self.__yaw, self.__pitch, 0)

    def __update(self, dx, dy, dz, rotateMode = True, zoomMode = True, isCallback = False):
        if isCallback:
            self.__autoUpdateCallbackId = BigWorld.callback(0.001, partial(self.__update, dx, dy, dz, rotateMode, zoomMode, True))
        cfg = self.__cfg
        if zoomMode and dz != 0:
            distRange = cfg['distRange']
            prevCam = self.__camDist
            self.__camDist -= dz * float(self.__curScrollSense)
            self.__camDist = _clamp(distRange[0], distRange[1], self.__camDist)
            self.__userCfg['startDist'] = self.__camDist
            if prevCam == self.__camDist and self.__onChangeControlMode is not None:
                if _almostZero(self.__camDist - distRange[0]):
                    self.__onChangeControlMode()
            self.__cam.pivotMaxDist = self.__camDist
        if rotateMode:
            matrix = Math.Matrix()
            matrix.setRotateYPR(self.__updateAngles(dx, dy))
            self.__cam.source = matrix
        return

    def __cameraUpdate(self):
        self.__cameraUpdateCallbackId = BigWorld.callback(0.0, self.__cameraUpdate)
        if self.__cam.target is None:
            self.__cam.pivotPosition = self.__defaultPivotPos
            return
        else:
            if self.__shiftKeySensor is not None:
                self.__shiftKeySensor.update(1.0)
                if self.__shiftKeySensor.currentVelocity.lengthSquared > 0.0:
                    currentShift = self.shiftCamPos(self.__shiftKeySensor.currentVelocity)
                    self.__shiftKeySensor.currentVelocity = Math.Vector3()
                    if currentShift.lengthSquared > 0.01:
                        return
            targetPosition = Math.Matrix(self.__cam.target).translation
            BOTTOM_SHIFT = Math.Vector3(0, 2.0, 0)
            collData = BigWorld.wg_collideSegment(BigWorld.player().spaceID, targetPosition + BOTTOM_SHIFT, targetPosition + Math.Vector3(0, self.__defaultPivotPos.y, 0), 7)
            if collData is not None:
                collPoint = collData[0]
                collNormal = collData[1]
                if collNormal.dot(Math.Vector3(0, -1, 0)) > 0:
                    self.__cam.pivotPosition = collPoint - Math.Vector3(0, 0.3, 0) - targetPosition
            else:
                self.__cam.pivotPosition = self.__defaultPivotPos
            return

    def handleKeyEvent(self, isDown, key, mods, event = None):
        if self.__shiftKeySensor is None:
            return False
        elif BigWorld.isKeyDown(Keys.KEY_CAPSLOCK) and mods & 4:
            if key == Keys.KEY_C:
                self.shiftCamPos()
            return self.__shiftKeySensor.handleKeyEvent(key, isDown)
        else:
            self.__shiftKeySensor.reset(Math.Vector3())
            return False