parent
0c7726d5c5
commit
7603a0f11b
@ -1,6 +1,8 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
|
||||
import com.otaliastudios.cameraview.CameraView; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
|
||||
/** |
@ -1,4 +1,4 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
/** |
||||
* Base interface for controls like {@link Audio}, |
@ -0,0 +1,72 @@ |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
import android.content.Context; |
||||
import android.content.res.TypedArray; |
||||
|
||||
import com.otaliastudios.cameraview.R; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
||||
/** |
||||
* Parses controls from XML attributes. |
||||
*/ |
||||
public class ControlParser { |
||||
|
||||
private int preview; |
||||
private int facing; |
||||
private int flash; |
||||
private int grid; |
||||
private int whiteBalance; |
||||
private int mode; |
||||
private int hdr; |
||||
private int audio; |
||||
private int videoCodec; |
||||
|
||||
public ControlParser(@NonNull Context context, @NonNull TypedArray array) { |
||||
this.preview = array.getInteger(R.styleable.CameraView_cameraPreview, Preview.DEFAULT.value()); |
||||
this.facing = array.getInteger(R.styleable.CameraView_cameraFacing, Facing.DEFAULT(context).value()); |
||||
this.flash = array.getInteger(R.styleable.CameraView_cameraFlash, Flash.DEFAULT.value()); |
||||
this.grid = array.getInteger(R.styleable.CameraView_cameraGrid, Grid.DEFAULT.value()); |
||||
this.whiteBalance = array.getInteger(R.styleable.CameraView_cameraWhiteBalance, WhiteBalance.DEFAULT.value()); |
||||
this.mode = array.getInteger(R.styleable.CameraView_cameraMode, Mode.DEFAULT.value()); |
||||
this.hdr = array.getInteger(R.styleable.CameraView_cameraHdr, Hdr.DEFAULT.value()); |
||||
this.audio = array.getInteger(R.styleable.CameraView_cameraAudio, Audio.DEFAULT.value()); |
||||
this.videoCodec = array.getInteger(R.styleable.CameraView_cameraVideoCodec, VideoCodec.DEFAULT.value()); |
||||
} |
||||
|
||||
public Preview getPreview() { |
||||
return Preview.fromValue(preview); |
||||
} |
||||
|
||||
public Facing getFacing() { |
||||
return Facing.fromValue(facing); |
||||
} |
||||
|
||||
public Flash getFlash() { |
||||
return Flash.fromValue(flash); |
||||
} |
||||
|
||||
public Grid getGrid() { |
||||
return Grid.fromValue(grid); |
||||
} |
||||
|
||||
public Mode getMode() { |
||||
return Mode.fromValue(mode); |
||||
} |
||||
|
||||
public WhiteBalance getWhiteBalance() { |
||||
return WhiteBalance.fromValue(whiteBalance); |
||||
} |
||||
|
||||
public Hdr getHdr() { |
||||
return Hdr.fromValue(hdr); |
||||
} |
||||
|
||||
public Audio getAudio() { |
||||
return Audio.fromValue(audio); |
||||
} |
||||
|
||||
public VideoCodec getVideoCodec() { |
||||
return VideoCodec.fromValue(videoCodec); |
||||
} |
||||
} |
@ -1,7 +1,11 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
|
||||
import android.content.Context; |
||||
|
||||
import com.otaliastudios.cameraview.CameraUtils; |
||||
import com.otaliastudios.cameraview.CameraView; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
import androidx.annotation.Nullable; |
||||
|
@ -1,6 +1,9 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
|
||||
import com.otaliastudios.cameraview.CameraOptions; |
||||
import com.otaliastudios.cameraview.CameraView; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
|
||||
/** |
@ -1,6 +1,8 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
|
||||
import com.otaliastudios.cameraview.CameraView; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
|
||||
/** |
@ -1,6 +1,8 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
|
||||
import com.otaliastudios.cameraview.CameraView; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
|
||||
/** |
@ -1,6 +1,8 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
|
||||
import com.otaliastudios.cameraview.CameraView; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
|
||||
import java.io.File; |
@ -1,6 +1,8 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
|
||||
import com.otaliastudios.cameraview.CameraView; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
|
||||
/** |
@ -1,7 +1,8 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
|
||||
import androidx.annotation.NonNull; |
||||
import com.otaliastudios.cameraview.CameraView; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
|
||||
/** |
@ -1,6 +1,9 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.controls; |
||||
|
||||
|
||||
import com.otaliastudios.cameraview.CameraOptions; |
||||
import com.otaliastudios.cameraview.CameraView; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
|
||||
/** |
@ -0,0 +1,159 @@ |
||||
package com.otaliastudios.cameraview.gesture; |
||||
|
||||
import android.content.Context; |
||||
import android.graphics.PointF; |
||||
import androidx.annotation.NonNull; |
||||
import android.view.MotionEvent; |
||||
import android.widget.FrameLayout; |
||||
|
||||
/** |
||||
* Base class for gesture layouts, that is, layouts that will capture |
||||
* gestures. |
||||
*/ |
||||
public abstract class GestureLayout extends FrameLayout { |
||||
|
||||
// The number of possible values between minValue and maxValue, for the getValue method.
|
||||
// We could make this non-static (e.g. larger granularity for exposure correction).
|
||||
private final static int GRANULARITY = 50; |
||||
private boolean mActive; |
||||
private Gesture mType; |
||||
private PointF[] mPoints; |
||||
|
||||
GestureLayout(@NonNull Context context, int points) { |
||||
super(context); |
||||
mPoints = new PointF[points]; |
||||
for (int i = 0; i < points; i++) { |
||||
mPoints[i] = new PointF(0, 0); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Makes this instance active, which means, listening to events. |
||||
* @param active whether this should be active or not |
||||
*/ |
||||
public void setActive(boolean active) { |
||||
mActive = active; |
||||
} |
||||
|
||||
/** |
||||
* Whether this instance is active, which means, it is listening |
||||
* to events and identifying new gestures. |
||||
* @return true if active |
||||
*/ |
||||
public boolean isActive() { |
||||
return mActive; |
||||
} |
||||
|
||||
/** |
||||
* Called when new events are available. |
||||
* If true is returned, users will call {@link #getGesture()}, {@link #getPoints()} |
||||
* and maybe {@link #getValue(float, float, float)} to know more about the gesture. |
||||
* |
||||
* @param event the new event |
||||
* @return true if a gesture was detected |
||||
*/ |
||||
public final boolean onTouchEvent(@NonNull MotionEvent event) { |
||||
if (!mActive) return false; |
||||
return handleTouchEvent(event); |
||||
} |
||||
|
||||
/** |
||||
* Called when new events are available. |
||||
* If true is returned, users will call {@link #getGesture()}, {@link #getPoints()} |
||||
* and maybe {@link #getValue(float, float, float)} to know more about the gesture. |
||||
* |
||||
* @param event the new event |
||||
* @return true if a gesture was detected |
||||
*/ |
||||
protected abstract boolean handleTouchEvent(@NonNull MotionEvent event); |
||||
|
||||
/** |
||||
* Returns the gesture that this instance is currently detecting. |
||||
* This is mutable - for instance, a scroll layout can detect both |
||||
* horizontal and vertical scroll gestures. |
||||
* |
||||
* @return the current gesture |
||||
*/ |
||||
@NonNull |
||||
public final Gesture getGesture() { |
||||
return mType; |
||||
} |
||||
|
||||
/** |
||||
* Sets the currently detected gesture. |
||||
* @see #getGesture() |
||||
* |
||||
* @param gesture the current gesture |
||||
*/ |
||||
protected final void setGesture(Gesture gesture) { |
||||
mType = gesture; |
||||
} |
||||
|
||||
/** |
||||
* Returns an array of points that identify the currently |
||||
* detected gesture. If no gesture was detected, this returns |
||||
* an array of points with x and y set to 0. |
||||
* |
||||
* @return array of gesture points |
||||
*/ |
||||
@NonNull |
||||
public final PointF[] getPoints() { |
||||
return mPoints; |
||||
} |
||||
|
||||
/** |
||||
* Utility function to access an item in the |
||||
* {@link #getPoints()} array. |
||||
* |
||||
* @param which the array position |
||||
* @return the point |
||||
*/ |
||||
@NonNull |
||||
protected final PointF getPoint(int which) { |
||||
return mPoints[which]; |
||||
} |
||||
|
||||
/** |
||||
* For {@link GestureType#CONTINUOUS} gestures, returns the float value at the current |
||||
* gesture state. This means, for example, scaling the old value with a pinch factor, |
||||
* taking into account the minimum and maximum values. |
||||
* |
||||
* @param currValue the last value |
||||
* @param minValue the min possible value |
||||
* @param maxValue the max possible value |
||||
* @return the new continuous value |
||||
*/ |
||||
public final float computeValue(float currValue, float minValue, float maxValue) { |
||||
return capValue(currValue, getValue(currValue, minValue, maxValue), minValue, maxValue); |
||||
} |
||||
|
||||
/** |
||||
* For {@link GestureType#CONTINUOUS} gestures, returns the float value at the current |
||||
* gesture state. This means, for example, scaling the old value with a pinch factor, |
||||
* taking into account the minimum and maximum values. |
||||
* |
||||
* @param currValue the last value |
||||
* @param minValue the min possible value |
||||
* @param maxValue the max possible value |
||||
* @return the new continuous value |
||||
*/ |
||||
protected abstract float getValue(float currValue, float minValue, float maxValue); |
||||
|
||||
/** |
||||
* Checks for newValue to be between minValue and maxValue, |
||||
* and checks that it is 'far enough' from the oldValue, in order |
||||
* to reduce useless updates. |
||||
*/ |
||||
private static float capValue(float oldValue, float newValue, float minValue, float maxValue) { |
||||
if (newValue < minValue) newValue = minValue; |
||||
if (newValue > maxValue) newValue = maxValue; |
||||
|
||||
float distance = (maxValue - minValue) / (float) GRANULARITY; |
||||
float half = distance / 2; |
||||
if (newValue >= oldValue - half && newValue <= oldValue + half) { |
||||
// Too close! Return the oldValue.
|
||||
return oldValue; |
||||
} |
||||
return newValue; |
||||
} |
||||
} |
@ -0,0 +1,53 @@ |
||||
package com.otaliastudios.cameraview.gesture; |
||||
|
||||
import android.content.Context; |
||||
import android.content.res.TypedArray; |
||||
|
||||
import com.otaliastudios.cameraview.R; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
||||
/** |
||||
* Parses gestures from XML attributes. |
||||
*/ |
||||
public class GestureParser { |
||||
|
||||
private int tapAction; |
||||
private int longTapAction; |
||||
private int pinchAction; |
||||
private int horizontalScrollAction; |
||||
private int verticalScrollAction; |
||||
|
||||
public GestureParser(@NonNull TypedArray array) { |
||||
this.tapAction = array.getInteger(R.styleable.CameraView_cameraGestureTap, GestureAction.DEFAULT_TAP.value()); |
||||
this.longTapAction = array.getInteger(R.styleable.CameraView_cameraGestureLongTap, GestureAction.DEFAULT_LONG_TAP.value()); |
||||
this.pinchAction = array.getInteger(R.styleable.CameraView_cameraGesturePinch, GestureAction.DEFAULT_PINCH.value()); |
||||
this.horizontalScrollAction = array.getInteger(R.styleable.CameraView_cameraGestureScrollHorizontal, GestureAction.DEFAULT_SCROLL_HORIZONTAL.value()); |
||||
this.verticalScrollAction = array.getInteger(R.styleable.CameraView_cameraGestureScrollVertical, GestureAction.DEFAULT_SCROLL_VERTICAL.value()); |
||||
} |
||||
|
||||
private GestureAction get(int which) { |
||||
return GestureAction.fromValue(which); |
||||
} |
||||
|
||||
public GestureAction getTapAction() { |
||||
return get(tapAction); |
||||
} |
||||
|
||||
public GestureAction getLongTapAction() { |
||||
return get(longTapAction); |
||||
} |
||||
|
||||
public GestureAction getPinchAction() { |
||||
return get(pinchAction); |
||||
} |
||||
|
||||
public GestureAction getHorizontalScrollAction() { |
||||
return get(horizontalScrollAction); |
||||
} |
||||
|
||||
public GestureAction getVerticalScrollAction() { |
||||
return get(verticalScrollAction); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,31 @@ |
||||
package com.otaliastudios.cameraview.gesture; |
||||
|
||||
|
||||
import com.otaliastudios.cameraview.CameraView; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
||||
|
||||
/** |
||||
* Gestures and gesture actions can both have a type. For a gesture to be able to be mapped to |
||||
* a certain {@link GestureAction}, both of them might be of the same type. |
||||
*/ |
||||
public enum GestureType { |
||||
|
||||
/** |
||||
* Defines gestures or gesture actions that consist of a single operation. |
||||
* Gesture example: a tap. |
||||
* Gesture action example: taking a picture. |
||||
*/ |
||||
ONE_SHOT, |
||||
|
||||
/** |
||||
* Defines gestures or gesture actions that consist of a continuous operation. |
||||
* Gesture example: pinching. |
||||
* Gesture action example: controlling zoom. |
||||
*/ |
||||
CONTINUOUS |
||||
} |
@ -1,4 +1,6 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.size; |
||||
|
||||
import com.otaliastudios.cameraview.size.Size; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
@ -0,0 +1,102 @@ |
||||
package com.otaliastudios.cameraview.size; |
||||
|
||||
import android.content.Context; |
||||
import android.content.res.TypedArray; |
||||
|
||||
import com.otaliastudios.cameraview.R; |
||||
import com.otaliastudios.cameraview.controls.Audio; |
||||
import com.otaliastudios.cameraview.controls.Facing; |
||||
import com.otaliastudios.cameraview.controls.Flash; |
||||
import com.otaliastudios.cameraview.controls.Grid; |
||||
import com.otaliastudios.cameraview.controls.Hdr; |
||||
import com.otaliastudios.cameraview.controls.Mode; |
||||
import com.otaliastudios.cameraview.controls.Preview; |
||||
import com.otaliastudios.cameraview.controls.VideoCodec; |
||||
import com.otaliastudios.cameraview.controls.WhiteBalance; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
||||
/** |
||||
* Parses size selectors from XML attributes. |
||||
*/ |
||||
public class SizeSelectorParser { |
||||
|
||||
private SizeSelector pictureSizeSelector; |
||||
private SizeSelector videoSizeSelector; |
||||
|
||||
public SizeSelectorParser(@NonNull TypedArray array) { |
||||
List<SizeSelector> pictureConstraints = new ArrayList<>(3); |
||||
if (array.hasValue(R.styleable.CameraView_cameraPictureSizeMinWidth)) { |
||||
pictureConstraints.add(SizeSelectors.minWidth(array.getInteger(R.styleable.CameraView_cameraPictureSizeMinWidth, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraPictureSizeMaxWidth)) { |
||||
pictureConstraints.add(SizeSelectors.maxWidth(array.getInteger(R.styleable.CameraView_cameraPictureSizeMaxWidth, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraPictureSizeMinHeight)) { |
||||
pictureConstraints.add(SizeSelectors.minHeight(array.getInteger(R.styleable.CameraView_cameraPictureSizeMinHeight, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraPictureSizeMaxHeight)) { |
||||
pictureConstraints.add(SizeSelectors.maxHeight(array.getInteger(R.styleable.CameraView_cameraPictureSizeMaxHeight, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraPictureSizeMinArea)) { |
||||
pictureConstraints.add(SizeSelectors.minArea(array.getInteger(R.styleable.CameraView_cameraPictureSizeMinArea, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraPictureSizeMaxArea)) { |
||||
pictureConstraints.add(SizeSelectors.maxArea(array.getInteger(R.styleable.CameraView_cameraPictureSizeMaxArea, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraPictureSizeAspectRatio)) { |
||||
//noinspection ConstantConditions
|
||||
pictureConstraints.add(SizeSelectors.aspectRatio(AspectRatio.parse(array.getString(R.styleable.CameraView_cameraPictureSizeAspectRatio)), 0)); |
||||
} |
||||
|
||||
if (array.getBoolean(R.styleable.CameraView_cameraPictureSizeSmallest, false)) pictureConstraints.add(SizeSelectors.smallest()); |
||||
if (array.getBoolean(R.styleable.CameraView_cameraPictureSizeBiggest, false)) pictureConstraints.add(SizeSelectors.biggest()); |
||||
pictureSizeSelector = !pictureConstraints.isEmpty() ? |
||||
SizeSelectors.and(pictureConstraints.toArray(new SizeSelector[0])) : |
||||
SizeSelectors.biggest(); |
||||
|
||||
// Video size selector
|
||||
List<SizeSelector> videoConstraints = new ArrayList<>(3); |
||||
if (array.hasValue(R.styleable.CameraView_cameraVideoSizeMinWidth)) { |
||||
videoConstraints.add(SizeSelectors.minWidth(array.getInteger(R.styleable.CameraView_cameraVideoSizeMinWidth, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraVideoSizeMaxWidth)) { |
||||
videoConstraints.add(SizeSelectors.maxWidth(array.getInteger(R.styleable.CameraView_cameraVideoSizeMaxWidth, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraVideoSizeMinHeight)) { |
||||
videoConstraints.add(SizeSelectors.minHeight(array.getInteger(R.styleable.CameraView_cameraVideoSizeMinHeight, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraVideoSizeMaxHeight)) { |
||||
videoConstraints.add(SizeSelectors.maxHeight(array.getInteger(R.styleable.CameraView_cameraVideoSizeMaxHeight, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraVideoSizeMinArea)) { |
||||
videoConstraints.add(SizeSelectors.minArea(array.getInteger(R.styleable.CameraView_cameraVideoSizeMinArea, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraVideoSizeMaxArea)) { |
||||
videoConstraints.add(SizeSelectors.maxArea(array.getInteger(R.styleable.CameraView_cameraVideoSizeMaxArea, 0))); |
||||
} |
||||
if (array.hasValue(R.styleable.CameraView_cameraVideoSizeAspectRatio)) { |
||||
//noinspection ConstantConditions
|
||||
videoConstraints.add(SizeSelectors.aspectRatio(AspectRatio.parse(array.getString(R.styleable.CameraView_cameraVideoSizeAspectRatio)), 0)); |
||||
} |
||||
if (array.getBoolean(R.styleable.CameraView_cameraVideoSizeSmallest, false)) videoConstraints.add(SizeSelectors.smallest()); |
||||
if (array.getBoolean(R.styleable.CameraView_cameraVideoSizeBiggest, false)) videoConstraints.add(SizeSelectors.biggest()); |
||||
videoSizeSelector = !videoConstraints.isEmpty() ? |
||||
SizeSelectors.and(videoConstraints.toArray(new SizeSelector[0])) : |
||||
SizeSelectors.biggest(); |
||||
} |
||||
|
||||
@NonNull |
||||
public SizeSelector getPictureSizeSelector() { |
||||
return pictureSizeSelector; |
||||
} |
||||
|
||||
@NonNull |
||||
public SizeSelector getVideoSizeSelector() { |
||||
return videoSizeSelector; |
||||
} |
||||
|
||||
} |
@ -1,4 +1,8 @@ |
||||
package com.otaliastudios.cameraview; |
||||
package com.otaliastudios.cameraview.size; |
||||
|
||||
import com.otaliastudios.cameraview.size.AspectRatio; |
||||
import com.otaliastudios.cameraview.size.Size; |
||||
import com.otaliastudios.cameraview.size.SizeSelector; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
@ -1,70 +0,0 @@ |
||||
package com.otaliastudios.cameraview; |
||||
|
||||
import android.content.Context; |
||||
import android.graphics.PointF; |
||||
import androidx.annotation.NonNull; |
||||
import android.view.MotionEvent; |
||||
import android.widget.FrameLayout; |
||||
|
||||
abstract class GestureLayout extends FrameLayout { |
||||
|
||||
// The number of possible values between minValue and maxValue, for the scaleValue method.
|
||||
// We could make this non-static (e.g. larger granularity for exposure correction).
|
||||
private final static int GRANULARITY = 50; |
||||
|
||||
protected boolean mEnabled; |
||||
protected Gesture mType; |
||||
protected PointF[] mPoints; |
||||
|
||||
public GestureLayout(@NonNull Context context) { |
||||
super(context); |
||||
onInitialize(context); |
||||
} |
||||
|
||||
protected void onInitialize(@NonNull Context context) { |
||||
} |
||||
|
||||
public void enable(boolean enable) { |
||||
mEnabled = enable; |
||||
} |
||||
|
||||
public boolean enabled() { |
||||
return mEnabled; |
||||
} |
||||
|
||||
public abstract boolean onTouchEvent(MotionEvent event); |
||||
|
||||
@NonNull |
||||
public final Gesture getGestureType() { |
||||
return mType; |
||||
} |
||||
|
||||
// For tests.
|
||||
void setGestureType(@NonNull Gesture type) { |
||||
mType = type; |
||||
} |
||||
|
||||
@NonNull |
||||
public final PointF[] getPoints() { |
||||
return mPoints; |
||||
} |
||||
|
||||
// Implementors should call capValue at the end.
|
||||
public abstract float scaleValue(float currValue, float minValue, float maxValue); |
||||
|
||||
// Checks for newValue to be between minValue and maxValue,
|
||||
// and checks that it is 'far enough' from the oldValue, in order
|
||||
// to reduce useless updates.
|
||||
protected static float capValue(float oldValue, float newValue, float minValue, float maxValue) { |
||||
if (newValue < minValue) newValue = minValue; |
||||
if (newValue > maxValue) newValue = maxValue; |
||||
|
||||
float distance = (maxValue - minValue) / (float) GRANULARITY; |
||||
float half = distance / 2; |
||||
if (newValue >= oldValue - half && newValue <= oldValue + half) { |
||||
// Too close! Return the oldValue.
|
||||
return oldValue; |
||||
} |
||||
return newValue; |
||||
} |
||||
} |
Loading…
Reference in new issue