From 5f13961d05266480a09a4bd8807a1a3f291eb145 Mon Sep 17 00:00:00 2001 From: utkabobr Date: Fri, 4 Apr 2025 19:18:57 +0300 Subject: [PATCH] Long click to move; Boosty page on click before redirect --- .../ru/ytkab0bp/slicebeam/SetupActivity.java | 56 +++++++++++--- .../components/bed_menu/OrientationMenu.java | 21 +++++- .../events/LongClickTranslationEvent.java | 16 ++++ .../slicebeam/fragment/SettingsFragment.java | 2 +- .../navigation/MobileNavigationDelegate.java | 12 +++ .../ru/ytkab0bp/slicebeam/render/Camera.java | 8 +- .../ytkab0bp/slicebeam/render/GLRenderer.java | 12 ++- .../ru/ytkab0bp/slicebeam/slic3r/Bed3D.java | 5 ++ .../ru/ytkab0bp/slicebeam/slic3r/Native.java | 1 + .../ru/ytkab0bp/slicebeam/view/GLView.java | 74 +++++++++++++++++-- .../slicebeam/view/SnackbarsLayout.java | 4 + app/src/main/jni/slicebeam/beam_native.cpp | 13 ++++ app/src/main/jni/slicebeam/bed_utils.hpp | 16 ++++ 13 files changed, 215 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/events/LongClickTranslationEvent.java diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/SetupActivity.java b/app/src/main/java/ru/ytkab0bp/slicebeam/SetupActivity.java index 6f78c2d..ab17de4 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/SetupActivity.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/SetupActivity.java @@ -8,11 +8,19 @@ import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.ColorStateList; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; import android.graphics.Typeface; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.opengl.GLSurfaceView; import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextUtils; +import android.text.style.ImageSpan; +import android.text.style.ReplacementSpan; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; @@ -30,6 +38,7 @@ import androidx.activity.EdgeToEdge; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; @@ -94,9 +103,11 @@ import ru.ytkab0bp.slicebeam.view.BeamSwitch; import ru.ytkab0bp.slicebeam.view.BoostySubsView; import ru.ytkab0bp.slicebeam.view.FadeRecyclerView; import ru.ytkab0bp.slicebeam.view.MiniColorView; +import ru.ytkab0bp.slicebeam.view.TextColorImageSpan; public class SetupActivity extends AppCompatActivity { public final static String EXTRA_ABOUT = "about"; + public final static String EXTRA_BOOSTY_ONLY = "boosty_only"; private final static String TAG = "SetupActivity"; @@ -137,6 +148,7 @@ public class SetupActivity extends AppCompatActivity { private Map> profilesMap = new HashMap<>(); private boolean isProfilesLoaded; private boolean about; + private boolean boostyOnly; private List enabledPrinters = new ArrayList<>(); @@ -153,8 +165,9 @@ public class SetupActivity extends AppCompatActivity { SliceBeam.EVENT_BUS.registerListener(this); about = getIntent().getBooleanExtra(EXTRA_ABOUT, false); + boostyOnly = getIntent().getBooleanExtra(EXTRA_BOOSTY_ONLY, false); - if (!about) { + if (!about && !boostyOnly) { new BeamAlertDialogBuilder(this) .setTitle(R.string.IntroEarlyAccess) .setMessage(R.string.IntroEarlyAccessMessage) @@ -166,7 +179,7 @@ public class SetupActivity extends AppCompatActivity { adapter = new SimpleRecyclerAdapter() { @Override public int getItemCount() { - return about ? 1 : limitRepoFragmentCount ? REPOS_INDEX + 1 : limitProfileFragmentCount ? PROFILES_INDEX + 1 : super.getItemCount(); + return about || boostyOnly ? 1 : limitRepoFragmentCount ? REPOS_INDEX + 1 : limitProfileFragmentCount ? PROFILES_INDEX + 1 : super.getItemCount(); } }; setItems(); @@ -197,13 +210,15 @@ public class SetupActivity extends AppCompatActivity { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - if (position == 0) { + if (position == 0 && !boostyOnly) { backgroundProgress = positionOffset; } else { backgroundProgress = 1f; } - if (position == BOOSTY_INDEX) { + if (boostyOnly) { + boostyProgress = 1f; + } else if (position == BOOSTY_INDEX) { boostyProgress = 1f - positionOffset; } else if (position == BOOSTY_INDEX - 1) { boostyProgress = positionOffset; @@ -462,7 +477,9 @@ public class SetupActivity extends AppCompatActivity { } private void setItems() { - if (about) { + if (boostyOnly) { + adapter.setItems(Collections.singletonList(new BoostyItem())); + } else if (about) { adapter.setItems(Collections.singletonList(new AboutItem())); } else { List items = new ArrayList<>(Arrays.asList( @@ -1008,25 +1025,42 @@ public class SetupActivity extends AppCompatActivity { }}); TextView subscribeButton = new TextView(ctx); - subscribeButton.setText(R.string.IntroBoostySupport); + SpannableStringBuilder sb = SpannableStringBuilder.valueOf(ctx.getString(R.string.IntroBoostySupport)).append(" "); + Drawable dr = ContextCompat.getDrawable(ctx, R.drawable.external_link_outline_24); + int size = ViewUtils.dp(16); + dr.setBounds(0, 0, size, size); + sb.append("d", new TextColorImageSpan(dr, ViewUtils.dp(2f)), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); + subscribeButton.setText(sb); subscribeButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - subscribeButton.setTextColor(ThemesRepo.getColor(R.attr.boostyColorTop)); + subscribeButton.setTextColor(Color.WHITE); subscribeButton.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); subscribeButton.setGravity(Gravity.CENTER); subscribeButton.setPadding(ViewUtils.dp(12), ViewUtils.dp(8), ViewUtils.dp(12), ViewUtils.dp(8)); + subscribeButton.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 16)); subscribeButton.setOnClickListener(v -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://boosty.to/ytkab0bp")))); - ll.addView(subscribeButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ - bottomMargin = ViewUtils.dp(12); + ll.addView(subscribeButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(52)) {{ + leftMargin = rightMargin = ViewUtils.dp(16); + bottomMargin = ViewUtils.dp(8); }}); TextView buttonView = new TextView(ctx); - buttonView.setText(R.string.IntroNext); + if (boostyOnly) { + buttonView.setText(android.R.string.ok); + } else { + buttonView.setText(R.string.IntroNext); + } buttonView.setTextColor(ThemesRepo.getColor(R.attr.textColorOnAccent)); buttonView.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); buttonView.setGravity(Gravity.CENTER); buttonView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); buttonView.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), ThemesRepo.getColor(R.attr.boostyColorTop), 16)); - buttonView.setOnClickListener(v-> scrollToNext()); + buttonView.setOnClickListener(v-> { + if (boostyOnly) { + finish(); + return; + } + scrollToNext(); + }); ll.addView(buttonView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(52)) {{ leftMargin = rightMargin = ViewUtils.dp(16); bottomMargin = ViewUtils.dp(16); diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/OrientationMenu.java b/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/OrientationMenu.java index acfcc80..c49d05c 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/OrientationMenu.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/OrientationMenu.java @@ -31,6 +31,7 @@ import ru.ytkab0bp.slicebeam.SliceBeam; import ru.ytkab0bp.slicebeam.components.BeamAlertDialogBuilder; import ru.ytkab0bp.slicebeam.components.UnfoldMenu; import ru.ytkab0bp.slicebeam.events.FlattenModeResetEvent; +import ru.ytkab0bp.slicebeam.events.LongClickTranslationEvent; import ru.ytkab0bp.slicebeam.events.NeedSnackbarEvent; import ru.ytkab0bp.slicebeam.events.ObjectsListChangedEvent; import ru.ytkab0bp.slicebeam.events.SelectedObjectChangedEvent; @@ -139,7 +140,7 @@ public class OrientationMenu extends ListBedMenu { private Vec3d tempVec = new Vec3d(); private int startedScrollObject; - private void translateVisual(Double x, Double y, Double z) { + public void translateVisual(Double x, Double y, Double z) { int j = fragment.getGlView().getRenderer().getSelectedObject(); if (j == -1) return; startedScrollObject = j; @@ -395,6 +396,24 @@ public class OrientationMenu extends ListBedMenu { startedScrollObject = -1; } + @EventHandler(runOnMainThread = true) + public void onLongClickTranslation(LongClickTranslationEvent e) { + if (e.visual) { + int j = fragment.getGlView().getRenderer().getSelectedObject(); + if (j == -1) return; + + Model model = fragment.getGlView().getRenderer().getModel(); + model.getTranslation(j, tempVec); + + xTitle.setText(formatTrackTitle(R.string.MenuOrientationPositionXValue, tempVec.x + e.x)); + yTitle.setText(formatTrackTitle(R.string.MenuOrientationPositionYValue, tempVec.y + e.y)); + xTrack.setCurrentPosition((int) (tempVec.x + e.x)); + yTrack.setCurrentPosition((int) (tempVec.y + e.y)); + } else { + setSelectionValues(); + } + } + @EventHandler(runOnMainThread = true) public void onSelectedObjectChanged(SelectedObjectChangedEvent e) { stopScroll(); diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/events/LongClickTranslationEvent.java b/app/src/main/java/ru/ytkab0bp/slicebeam/events/LongClickTranslationEvent.java new file mode 100644 index 0000000..ed8435b --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/events/LongClickTranslationEvent.java @@ -0,0 +1,16 @@ +package ru.ytkab0bp.slicebeam.events; + +import ru.ytkab0bp.eventbus.Event; + +@Event +public class LongClickTranslationEvent { + public final double x; + public final double y; + public final boolean visual; + + public LongClickTranslationEvent(double x, double y, boolean visual) { + this.x = x; + this.y = y; + this.visual = visual; + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/fragment/SettingsFragment.java b/app/src/main/java/ru/ytkab0bp/slicebeam/fragment/SettingsFragment.java index 2c19a8f..bfdbefb 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/fragment/SettingsFragment.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/fragment/SettingsFragment.java @@ -144,7 +144,7 @@ public class SettingsFragment extends ProfileListFragment { }), BeamServerData.isBoostyAvailable() ? new OptionElement(R.drawable.boosty, getContext().getString(R.string.SettingsBoosty)).setColor(R.attr.boostyColorTop, true).setOnClick(() -> { Activity act = (Activity) getContext(); - act.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://boosty.to/ytkab0bp"))); + act.startActivity(new Intent(act, SetupActivity.class).putExtra(SetupActivity.EXTRA_BOOSTY_ONLY, true)); }) : null, new OptionElement(R.drawable.k3d_logo_new_14, getContext().getString(R.string.SettingsK3D)).setColor(R.attr.k3dColor, true).setOnClick(() -> { Activity act = (Activity) getContext(); diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/navigation/MobileNavigationDelegate.java b/app/src/main/java/ru/ytkab0bp/slicebeam/navigation/MobileNavigationDelegate.java index 1396492..130a6bb 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/navigation/MobileNavigationDelegate.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/navigation/MobileNavigationDelegate.java @@ -107,6 +107,18 @@ public class MobileNavigationDelegate extends DelegateSlotImpl { return root = fl; } + @Override + public boolean onBackPressed() { + if (super.onBackPressed()) { + return true; + } + if (currentSlot != 0) { + switchSlot(0, () -> navigationView.setSelectedItemId(0)); + return true; + } + return false; + } + @Override public FrameLayout getOverlayView() { return root; diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/render/Camera.java b/app/src/main/java/ru/ytkab0bp/slicebeam/render/Camera.java index 0e949cc..f4fdfdd 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/render/Camera.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/render/Camera.java @@ -41,7 +41,7 @@ public class Camera { this.zoom = zoom; } - public void move(float x, float y) { + public Vec3d calcScreenMovement(float x, float y) { x /= zoom; y /= zoom; @@ -61,8 +61,10 @@ public class Camera { screenX.multiply(x); screenY.multiply(y); - Vec3d move = new Vec3d(screenX).add(screenY); - + return new Vec3d(screenX).add(screenY); + } + public void move(float x, float y) { + Vec3d move = calcScreenMovement(x, y); position.add(move); origin.add(move); } diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/render/GLRenderer.java b/app/src/main/java/ru/ytkab0bp/slicebeam/render/GLRenderer.java index 04f1d06..7e47ca7 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/render/GLRenderer.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/render/GLRenderer.java @@ -374,9 +374,8 @@ public class GLRenderer implements GLSurfaceView.Renderer { return true; } - public boolean onClick(float x, float y) { - if (model == null || isViewerEnabled) return false; - + public int raycastObjectIndex(float x, float y) { + if (model == null) return -1; double minDistance = Double.MAX_VALUE; int j = -1; for (int i = 0, c = model.getObjectsCount(); i < c; i++) { @@ -394,6 +393,13 @@ public class GLRenderer implements GLSurfaceView.Renderer { } } } + return j; + } + + public boolean onClick(float x, float y) { + if (model == null || isViewerEnabled) return false; + + int j = raycastObjectIndex(x, y); if (isInFlattenMode && (j == selectedObject || j == -1)) { int minPlane = -1; diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/slic3r/Bed3D.java b/app/src/main/java/ru/ytkab0bp/slicebeam/slic3r/Bed3D.java index 1518203..f2ae7aa 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/slic3r/Bed3D.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/slic3r/Bed3D.java @@ -45,6 +45,7 @@ public class Bed3D { private void configure(String path) { Native.bed_configure(pointer, path); + Native.bed_init_triangles_mesh(pointer, triangles.pointer); boundingVolume = Native.bed_get_bounding_volume(pointer); min = max = null; @@ -78,6 +79,10 @@ public class Bed3D { return boundingVolume != null; } + public GLModel.MeshRaycaster getRaycaster() { + return triangles.getRaycaster(); + } + public void render(boolean bottom, double[] viewModelMatrix, double[] projectionMatrix, float invZoom) { assertTrue(viewModelMatrix.length == 16); assertTrue(projectionMatrix.length == 16); diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/slic3r/Native.java b/app/src/main/java/ru/ytkab0bp/slicebeam/slic3r/Native.java index 27680a6..68291f8 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/slic3r/Native.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/slic3r/Native.java @@ -46,6 +46,7 @@ class Native { static native int bed_get_bounding_volume_max_size(long ptr); static native double[] bed_get_bounding_volume(long ptr); static native void bed_configure(long ptr, String configPath); + static native void bed_init_triangles_mesh(long ptr, long triangles); static native boolean bed_arrange(long ptr, long modelPtr); static native void bed_release(long ptr); diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/view/GLView.java b/app/src/main/java/ru/ytkab0bp/slicebeam/view/GLView.java index ae6fdc7..e8fba03 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/view/GLView.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/view/GLView.java @@ -17,17 +17,23 @@ import android.opengl.GLSurfaceView; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; +import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.ViewConfiguration; import java.nio.IntBuffer; +import java.util.ArrayList; import ru.ytkab0bp.slicebeam.R; +import ru.ytkab0bp.slicebeam.SliceBeam; +import ru.ytkab0bp.slicebeam.events.LongClickTranslationEvent; import ru.ytkab0bp.slicebeam.render.GLRenderer; +import ru.ytkab0bp.slicebeam.slic3r.GLModel; import ru.ytkab0bp.slicebeam.theme.IThemeView; import ru.ytkab0bp.slicebeam.theme.ThemesRepo; import ru.ytkab0bp.slicebeam.utils.Prefs; +import ru.ytkab0bp.slicebeam.utils.Vec3d; import ru.ytkab0bp.slicebeam.utils.ViewUtils; public class GLView extends GLSurfaceView implements IThemeView { @@ -40,9 +46,26 @@ public class GLView extends GLSurfaceView implements IThemeView { private boolean fromTwoPointers; private boolean onePointerGesture; private boolean twoPointerGesture; + private boolean longClickGesture; private boolean isScaling; + private Vec3d tempVec = new Vec3d(); + private Vec3d longClickOffset = new Vec3d(); + private Vec3d longClickTranslation = new Vec3d(); + private ArrayList longClickHitResults = new ArrayList<>(); private long lastActionTime = System.currentTimeMillis(); + private Runnable longClick = () -> { + getRenderer().getBed().getRaycaster().raycast(getRenderer(), longClickHitResults, lastX, lastY); + if (!longClickHitResults.isEmpty()) { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + longClickGesture = true; + + GLModel.HitResult result = longClickHitResults.get(0); + getRenderer().getModel().getTranslation(getRenderer().getSelectedObject(), tempVec); + longClickOffset.x = result.position.x - tempVec.x; + longClickOffset.y = result.position.y - tempVec.y; + } + }; private Path path = new Path(); private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -249,21 +272,43 @@ public class GLView extends GLSurfaceView implements IThemeView { int action = e.getActionMasked(); if (e.getPointerCount() > 2) { + removeCallbacks(longClick); + longClickGesture = false; return true; } if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) { if (e.getPointerCount() == 2) { + removeCallbacks(longClick); + longClickGesture = false; calcStartFocus(e); fromTwoPointers = true; } else { lastX = e.getX(); lastY = e.getY(); + + int j = renderer.raycastObjectIndex(lastX, lastY); + if (j == renderer.getSelectedObject() && j != -1) { + postDelayed(longClick, 300); + } } return true; } if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_CANCEL) { + removeCallbacks(longClick); + if (longClickGesture) { + queueEvent(()->{ + int j = getRenderer().getSelectedObject(); + getRenderer().getModel().getTranslation(j, tempVec); + getRenderer().setSelectionTranslation(0, 0, 0); + getRenderer().getModel().translate(j, longClickTranslation.x, longClickTranslation.y, 0); + getRenderer().invalidateGlModel(j); + requestRender(); + SliceBeam.EVENT_BUS.fireEvent(new LongClickTranslationEvent(longClickTranslation.x, longClickTranslation.y, false)); + }); + } + longClickGesture = false; if (fromTwoPointers) { if (e.getPointerCount() == 1) { fromTwoPointers = false; @@ -286,7 +331,7 @@ public class GLView extends GLSurfaceView implements IThemeView { onePointerGesture = false; } - // TODO: Rotate with inertia + // TODO: Rotate with inertia? return true; } if (action == MotionEvent.ACTION_MOVE) { @@ -347,18 +392,35 @@ public class GLView extends GLSurfaceView implements IThemeView { if (Math.sqrt(distanceX * distanceX + distanceY * distanceY) >= touchSlop) { onePointerGesture = true; startingGesture = true; + removeCallbacks(longClick); } } if (onePointerGesture) { if (!startingGesture) { - int mode = Prefs.getCameraControlMode(); - if (mode == Prefs.CAMERA_CONTROL_MODE_ROTATE_MOVE) { - renderer.getCamera().rotateAround(distanceX / touchSlop * Prefs.getCameraSensitivity(), distanceY / touchSlop * Prefs.getCameraSensitivity()); + if (longClickGesture) { + Vec3d move = getRenderer().getCamera().calcScreenMovement(distanceX / touchSlop * 4.5f, distanceY / touchSlop * 4.5f); + + getRenderer().getModel().getTranslation(getRenderer().getSelectedObject(), tempVec); + getRenderer().getBed().getRaycaster().raycast(getRenderer(), longClickHitResults, e.getX(), e.getY()); + if (!longClickHitResults.isEmpty()) { + GLModel.HitResult result = longClickHitResults.get(0); + longClickTranslation.x = result.position.x - tempVec.x - longClickOffset.x; + longClickTranslation.y = result.position.y - tempVec.y - longClickOffset.y; + getRenderer().setSelectionTranslation(longClickTranslation.x, longClickTranslation.y, 0); + SliceBeam.EVENT_BUS.fireEvent(new LongClickTranslationEvent(longClickTranslation.x, longClickTranslation.y, true)); + } + + requestRender(); } else { - renderer.getCamera().move(distanceX / touchSlop * Prefs.getCameraSensitivity(), distanceY / touchSlop * Prefs.getCameraSensitivity()); + int mode = Prefs.getCameraControlMode(); + if (mode == Prefs.CAMERA_CONTROL_MODE_ROTATE_MOVE) { + renderer.getCamera().rotateAround(distanceX / touchSlop * Prefs.getCameraSensitivity(), distanceY / touchSlop * Prefs.getCameraSensitivity()); + } else { + renderer.getCamera().move(distanceX / touchSlop * Prefs.getCameraSensitivity(), distanceY / touchSlop * Prefs.getCameraSensitivity()); + } + requestRender(); } - requestRender(); } lastX = e.getX(); diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/view/SnackbarsLayout.java b/app/src/main/java/ru/ytkab0bp/slicebeam/view/SnackbarsLayout.java index 72b6e3f..e93366c 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/view/SnackbarsLayout.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/view/SnackbarsLayout.java @@ -37,6 +37,10 @@ public class SnackbarsLayout extends FrameLayout { } public void show(Snackbar snackbar) { + if (snackbar.tag != null) { + dismiss(snackbar.tag); + } + SnackbarView v = new SnackbarView(getContext()).bind(snackbar); addView(v); applyTransforms(); diff --git a/app/src/main/jni/slicebeam/beam_native.cpp b/app/src/main/jni/slicebeam/beam_native.cpp index a4b6ca3..ede0af4 100644 --- a/app/src/main/jni/slicebeam/beam_native.cpp +++ b/app/src/main/jni/slicebeam/beam_native.cpp @@ -1401,6 +1401,19 @@ extern "C" { bed_util_init_contourlines(ref->contour, ref->contourlines); } + JNIEXPORT void JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_bed_1init_1triangles_1mesh(JNIEnv* env, jclass, jlong ptr, jlong triangles_ptr) { + auto ref = reinterpret_cast(ptr); + auto tRef = reinterpret_cast(triangles_ptr); + + auto contour = ref->contour; + BoundingBox bb = get_extents(contour); + Point center = bb.center(); + float scaleFactor = 4; + contour.scale(scaleFactor); + contour.translate(-center.x() * scaleFactor * 0.5f, -center.y() * scaleFactor * 0.5f); + bed_util_init_triangles_its(contour, &tRef->mesh.its); + } + JNIEXPORT jboolean JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_bed_1arrange(JNIEnv* env, jclass, jlong ptr, jlong model) { BedRef* ref = (BedRef*) (intptr_t) ptr; ModelRef* mRef = (ModelRef*) (intptr_t) model; diff --git a/app/src/main/jni/slicebeam/bed_utils.hpp b/app/src/main/jni/slicebeam/bed_utils.hpp index 75ada3d..f18659b 100644 --- a/app/src/main/jni/slicebeam/bed_utils.hpp +++ b/app/src/main/jni/slicebeam/bed_utils.hpp @@ -56,6 +56,22 @@ void bed_util_init_gridlines(ExPolygon& contour, GLModel* glGridlines) { glGridlines->init_from(std::move(init_data)); } +void bed_util_init_triangles_its(ExPolygon& contour, indexed_triangle_set* its) { + if (contour.empty()) + return; + + auto triangles = triangulate_expolygon_3d(contour, 0); + its->vertices.reserve(triangles.size()); + + for (size_t i = 0; i < triangles.size(); i += 3) { + its->vertices.emplace_back(triangles[i].cast()); + its->vertices.emplace_back(triangles[i + 1].cast()); + its->vertices.emplace_back(triangles[i + 2].cast()); + + its->indices.emplace_back(i, i + 1, i + 2); + } +} + void bed_util_init_triangles(ExPolygon& contour, GLModel* glTriangles) { if (glTriangles->is_initialized()) return;