mirror of
https://github.com/Dark98/SliceBeam.git
synced 2026-07-06 16:49:05 +00:00
Public source code release
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import static android.opengl.GLES30.*;
|
||||
import static ru.ytkab0bp.slicebeam.utils.DebugUtils.assertTrue;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.R;
|
||||
import ru.ytkab0bp.slicebeam.render.CoordAxes;
|
||||
import ru.ytkab0bp.slicebeam.theme.ThemesRepo;
|
||||
import ru.ytkab0bp.slicebeam.utils.DoubleMatrix;
|
||||
import ru.ytkab0bp.slicebeam.utils.Vec3d;
|
||||
import ru.ytkab0bp.slicebeam.utils.ViewUtils;
|
||||
|
||||
public class Bed3D {
|
||||
private final static float GROUND_Z = -0.02f;
|
||||
|
||||
private long pointer;
|
||||
|
||||
private GLModel triangles;
|
||||
private GLModel gridlines;
|
||||
private GLModel contourlines;
|
||||
|
||||
private CoordAxes axes = new CoordAxes();
|
||||
private double[] boundingVolume;
|
||||
private Vec3d min, max;
|
||||
|
||||
private boolean likelyDelta;
|
||||
|
||||
private double[] modelMatrix = new double[16];
|
||||
private double[] outModelMatrix = new double[16];
|
||||
|
||||
public Bed3D() {
|
||||
long[] data = new long[3];
|
||||
pointer = Native.bed_create(data);
|
||||
triangles = new GLModel(data[0]);
|
||||
gridlines = new GLModel(data[1]);
|
||||
contourlines = new GLModel(data[2]);
|
||||
}
|
||||
|
||||
public void configure(File f) {
|
||||
configure(f.getAbsolutePath());
|
||||
}
|
||||
|
||||
private void configure(String path) {
|
||||
Native.bed_configure(pointer, path);
|
||||
boundingVolume = Native.bed_get_bounding_volume(pointer);
|
||||
|
||||
min = max = null;
|
||||
|
||||
axes.origin.set(0, 0, GROUND_Z);
|
||||
axes.setStemLength(0.1f * Native.bed_get_bounding_volume_max_size(pointer));
|
||||
|
||||
if (isValid()) {
|
||||
Vec3d center = getVolumeMin().center(getVolumeMax());
|
||||
likelyDelta = (center.x == 0 || center.y == 0) && getVolumeMin().x < 0 && getVolumeMin().y < 0;
|
||||
} else {
|
||||
likelyDelta = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void arrange(Model model) {
|
||||
Native.bed_arrange(pointer, model.pointer);
|
||||
}
|
||||
|
||||
public Vec3d getVolumeMin() {
|
||||
if (min == null && boundingVolume != null) min = new Vec3d(boundingVolume[0], boundingVolume[1], boundingVolume[2]);
|
||||
return min;
|
||||
}
|
||||
|
||||
public Vec3d getVolumeMax() {
|
||||
if (max == null && boundingVolume != null) max = new Vec3d(boundingVolume[3], boundingVolume[4], boundingVolume[5]);
|
||||
return max;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return boundingVolume != null;
|
||||
}
|
||||
|
||||
public void render(boolean bottom, double[] viewModelMatrix, double[] projectionMatrix, float invZoom) {
|
||||
assertTrue(viewModelMatrix.length == 16);
|
||||
assertTrue(projectionMatrix.length == 16);
|
||||
|
||||
DoubleMatrix.setIdentityM(modelMatrix, 0);
|
||||
if (!likelyDelta) {
|
||||
DoubleMatrix.translateM(modelMatrix, 0, -getVolumeMin().x * 2, -getVolumeMin().y * 2, -getVolumeMin().z);
|
||||
}
|
||||
DoubleMatrix.multiplyMM(outModelMatrix, 0, viewModelMatrix, 0, modelMatrix, 0);
|
||||
renderDefaultBed(bottom, outModelMatrix, projectionMatrix);
|
||||
axes.render(viewModelMatrix, projectionMatrix, 0.25f, invZoom);
|
||||
}
|
||||
|
||||
private void renderDefaultBed(boolean bottom, double[] viewModelMatrix, double[] projectionMatrix) {
|
||||
GLShaderProgram shader = GLShadersManager.get(GLShadersManager.SHADER_FLAT);
|
||||
shader.startUsing();
|
||||
|
||||
shader.setUniformMatrix4fv("view_model_matrix", viewModelMatrix);
|
||||
shader.setUniformMatrix4fv("projection_matrix", projectionMatrix);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
if (!bottom) {
|
||||
glDepthMask(false);
|
||||
triangles.setColor(ThemesRepo.getColor(R.attr.defaultBedColor));
|
||||
triangles.render();
|
||||
glDepthMask(true);
|
||||
}
|
||||
|
||||
glLineWidth(ViewUtils.dp(1));
|
||||
gridlines.setColor(ThemesRepo.getColor(R.attr.bedGridlinesColor));
|
||||
gridlines.render();
|
||||
|
||||
contourlines.setColor(ThemesRepo.getColor(R.attr.bedContourlinesColor));
|
||||
contourlines.render();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
shader.stopUsing();
|
||||
}
|
||||
|
||||
private void renderTexturedBed(boolean bottom, float[] viewModelMatrix, float[] projectionMatrix) {
|
||||
GLShaderProgram shader = GLShadersManager.get(GLShadersManager.SHADER_PRINTBED);
|
||||
shader.startUsing();
|
||||
|
||||
shader.setUniform3f("view_model_matrix", viewModelMatrix);
|
||||
shader.setUniform3f("projection_matrix", projectionMatrix);
|
||||
shader.setUniform("transparent_background", bottom);
|
||||
shader.setUniform("svg_source", false);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
if (bottom) {
|
||||
glDepthMask(false);
|
||||
}
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
if (bottom) {
|
||||
glFrontFace(GL_CW);
|
||||
}
|
||||
|
||||
// TODO: glBindTexture(GL_TEXTURE_2D, tex_id);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
if (bottom) {
|
||||
glFrontFace(GL_CCW);
|
||||
}
|
||||
glDisable(GL_BLEND);
|
||||
if (bottom) {
|
||||
glDepthMask(true);
|
||||
}
|
||||
|
||||
shader.stopUsing();
|
||||
}
|
||||
|
||||
public void release() {
|
||||
Native.bed_release(pointer);
|
||||
axes.release();
|
||||
|
||||
// triangles.release();
|
||||
// gridlines.release();
|
||||
// contourlines.release();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
@Keep
|
||||
public class ConfigOptionDef {
|
||||
public String key;
|
||||
|
||||
// What type? bool, int, string etc.
|
||||
public ConfigOptionType type = ConfigOptionType.NONE;
|
||||
|
||||
// Usually empty.
|
||||
// Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection,
|
||||
// "select_open" - to open a selection dialog (currently only a serial port selection).
|
||||
public GUIType guiType;
|
||||
|
||||
// Label of the GUI input field.
|
||||
// In case the GUI input fields are grouped in some views, the label defines a short label of a grouped value,
|
||||
// while full_label contains a label of a stand-alone field.
|
||||
// The full label is shown, when adding an override parameter for an object or a modified object.
|
||||
public String label;
|
||||
public String fullLabel;
|
||||
|
||||
// With which printer technology is this configuration valid?
|
||||
public PrinterTechnology printerTechnology = PrinterTechnology.UNKNOWN;
|
||||
|
||||
// Category of a configuration field, from the GUI perspective.
|
||||
// One of: "Layers and Perimeters", "Infill", "Support material", "Speed", "Extruders", "Advanced", "Extrusion Width"
|
||||
public String category;
|
||||
|
||||
// A tooltip text shown in the GUI.
|
||||
public String tooltip;
|
||||
|
||||
// Text right from the input field, usually a unit of measurement.
|
||||
public String sidetext;
|
||||
|
||||
// True for multiline strings.
|
||||
public boolean multiline;
|
||||
|
||||
// For text input: If true, the GUI text box spans the complete page width.
|
||||
public boolean fullWidth;
|
||||
|
||||
// Not editable. Currently only used for the display of the number of threads.
|
||||
public boolean readonly = false;
|
||||
|
||||
// Height of a multiline GUI text box.
|
||||
public int height = -1;
|
||||
|
||||
// Optional width of an input field.
|
||||
public int width = -1;
|
||||
|
||||
// <min, max> limit of a numeric input.
|
||||
// If not set, the <min, max> is set to <INT_MIN, INT_MAX>
|
||||
// By setting min=0, only nonnegative input is allowed.
|
||||
public float min = Float.MIN_VALUE;
|
||||
public float max = Float.MAX_VALUE;
|
||||
|
||||
public ConfigOptionMode mode = ConfigOptionMode.SIMPLE;
|
||||
|
||||
public String defaultValue;
|
||||
|
||||
public String[] enumLabels;
|
||||
public String[] enumValues;
|
||||
|
||||
public String getLabel() {
|
||||
return TextUtils.isEmpty(label) ? fullLabel : label;
|
||||
}
|
||||
|
||||
public String getFullLabel() {
|
||||
return TextUtils.isEmpty(fullLabel) ? label : fullLabel;
|
||||
}
|
||||
|
||||
ConfigOptionDef() {}
|
||||
|
||||
public enum ConfigOptionType {
|
||||
NONE,
|
||||
// single float
|
||||
FLOAT,
|
||||
// vector of floats
|
||||
FLOATS(true),
|
||||
// single int
|
||||
INT,
|
||||
// vector of ints
|
||||
INTS(true),
|
||||
// single string
|
||||
STRING,
|
||||
// vector of strings
|
||||
STRINGS(true),
|
||||
// percent value. Currently only used for infill.
|
||||
PERCENT,
|
||||
// percents value. Currently used for retract before wipe only.
|
||||
PERCENTS(true),
|
||||
// a fraction or an absolute value
|
||||
FLOAT_OR_PERCENT,
|
||||
// vector of the above
|
||||
FLOATS_OR_PERCENTS(true),
|
||||
// single 2d point (Point2f). Currently not used.
|
||||
POINT,
|
||||
// vector of 2d points (Point2f). Currently used for the definition of the print bed and for the extruder offsets.
|
||||
POINTS(true),
|
||||
POINT3,
|
||||
// single boolean value
|
||||
BOOL,
|
||||
// vector of boolean values
|
||||
BOOLS(true),
|
||||
// a generic enum
|
||||
ENUM,
|
||||
// vector of enum values
|
||||
ENUMS;
|
||||
|
||||
public final boolean list;
|
||||
|
||||
ConfigOptionType() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
ConfigOptionType(boolean list) {
|
||||
this.list = list;
|
||||
}
|
||||
}
|
||||
|
||||
public enum GUIType {
|
||||
UNDEFINED,
|
||||
// Open enums, integer value could be one of the enumerated values or something else.
|
||||
I_ENUM_OPEN,
|
||||
// Open enums, float value could be one of the enumerated values or something else.
|
||||
F_ENUM_OPEN,
|
||||
// Open enums, string value could be one of the enumerated values or something else.
|
||||
SELECT_OPEN,
|
||||
// Color picker, string value.
|
||||
COLOR,
|
||||
// Currently unused.
|
||||
SLIDER,
|
||||
// Static text
|
||||
LEGEND,
|
||||
// Vector value, but edited as a single string.
|
||||
ONE_STRING,
|
||||
// Close parameter, string value could be one of the list values.
|
||||
SELECT_CLOSE,
|
||||
// Password, string vaule is hidden by asterisk.
|
||||
PASSWORD
|
||||
}
|
||||
|
||||
public enum PrinterTechnology {
|
||||
// Fused Filament Fabrication
|
||||
FFF,
|
||||
// Stereolitography
|
||||
SLA,
|
||||
// Unknown, useful for command line processing
|
||||
UNKNOWN,
|
||||
// Any technology, useful for parameters compatible with both ptFFF and ptSLA
|
||||
ANY
|
||||
}
|
||||
|
||||
public enum ConfigOptionMode {
|
||||
SIMPLE,
|
||||
ADVANCED,
|
||||
EXPERT,
|
||||
UNDEFINED
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class GCodeProcessorResult {
|
||||
final long pointer;
|
||||
|
||||
public GCodeProcessorResult(File f) {
|
||||
pointer = Native.gcoderesult_load_file(f.getAbsolutePath(), f.getName());
|
||||
}
|
||||
|
||||
GCodeProcessorResult(long ptr) {
|
||||
pointer = ptr;
|
||||
}
|
||||
|
||||
public String getRecommendedName() {
|
||||
return Native.gcoderesult_get_recommended_name(pointer);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
Native.gcoderesult_release(pointer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import static ru.ytkab0bp.slicebeam.utils.DebugUtils.assertTrue;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.R;
|
||||
import ru.ytkab0bp.slicebeam.theme.ThemesRepo;
|
||||
|
||||
public class GCodeViewer {
|
||||
private ThreadLocal<float[]> viewMatrixBuffer = new ThreadLocal<float[]>() {
|
||||
@Override
|
||||
protected float[] initialValue() {
|
||||
return new float[16];
|
||||
}
|
||||
};
|
||||
private ThreadLocal<float[]> projectionMatrixBuffer = new ThreadLocal<float[]>() {
|
||||
@Override
|
||||
protected float[] initialValue() {
|
||||
return new float[16];
|
||||
}
|
||||
};
|
||||
|
||||
private final long pointer;
|
||||
|
||||
public GCodeViewer() {
|
||||
pointer = Native.vgcode_create();
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return Native.vgcode_is_initialized(pointer);
|
||||
}
|
||||
|
||||
public void initGL() {
|
||||
Native.vgcode_init(pointer);
|
||||
}
|
||||
|
||||
public void load(GCodeProcessorResult result) {
|
||||
Native.vgcode_load(pointer, result.pointer);
|
||||
}
|
||||
|
||||
public void setLayersViewRange(long min, long max) {
|
||||
Native.vgcode_set_layers_view_range(pointer, min, max);
|
||||
}
|
||||
|
||||
public Pair<Long, Long> getLayersViewRange() {
|
||||
long[] data = Native.vgcode_get_layers_view_range(pointer);
|
||||
return new Pair<>(data[0], data[1] < 0 ? getLayersCount() : data[1]);
|
||||
}
|
||||
|
||||
public long getLayersCount() {
|
||||
return Native.vgcode_get_layers_count(pointer);
|
||||
}
|
||||
|
||||
public void render(double[] viewMatrix, double[] projectionMatrix) {
|
||||
assertTrue(viewMatrix.length == 16);
|
||||
assertTrue(projectionMatrix.length == 16);
|
||||
|
||||
float[] vmFloats = viewMatrixBuffer.get();
|
||||
for (int i = 0; i < viewMatrix.length; i++) {
|
||||
vmFloats[i] = (float) viewMatrix[i];
|
||||
}
|
||||
float[] pmFloats = projectionMatrixBuffer.get();
|
||||
for (int i = 0; i < projectionMatrix.length; i++) {
|
||||
pmFloats[i] = (float) projectionMatrix[i];
|
||||
}
|
||||
Native.vgcode_render(pointer, vmFloats, pmFloats);
|
||||
}
|
||||
|
||||
public void setThemeColors() {
|
||||
setColors(
|
||||
ThemesRepo.getColor(R.attr.gcodeViewerSkirt),
|
||||
ThemesRepo.getColor(R.attr.gcodeViewerExternalPerimeter),
|
||||
ThemesRepo.getColor(R.attr.gcodeViewerSupportMaterial),
|
||||
ThemesRepo.getColor(R.attr.gcodeViewerSupportMaterialInterface),
|
||||
ThemesRepo.getColor(R.attr.gcodeViewerInternalInfill),
|
||||
ThemesRepo.getColor(R.attr.gcodeViewerSolidInfill),
|
||||
ThemesRepo.getColor(R.attr.gcodeViewerWipeTower)
|
||||
);
|
||||
}
|
||||
|
||||
public void setColors(int skirt, int externalPerimeter, int supportMaterial, int supportMaterialInterface, int internalInfill, int solidInfill, int wipeTower) {
|
||||
Native.vgcode_set_colors(pointer, new int[] {
|
||||
Color.red(skirt), Color.green(skirt), Color.blue(skirt),
|
||||
Color.red(externalPerimeter), Color.green(externalPerimeter), Color.blue(externalPerimeter),
|
||||
Color.red(supportMaterial), Color.green(supportMaterial), Color.blue(supportMaterial),
|
||||
Color.red(supportMaterialInterface), Color.green(supportMaterialInterface), Color.blue(supportMaterialInterface),
|
||||
Color.red(internalInfill), Color.green(internalInfill), Color.blue(internalInfill),
|
||||
Color.red(solidInfill), Color.green(solidInfill), Color.blue(solidInfill),
|
||||
Color.red(wipeTower), Color.green(wipeTower), Color.blue(wipeTower)
|
||||
});
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
Native.vgcode_reset(pointer);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
Native.vgcode_release(pointer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import static ru.ytkab0bp.slicebeam.utils.DebugUtils.assertTrue;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.render.Camera;
|
||||
import ru.ytkab0bp.slicebeam.render.GLRenderer;
|
||||
import ru.ytkab0bp.slicebeam.utils.Prefs;
|
||||
import ru.ytkab0bp.slicebeam.utils.Vec3d;
|
||||
|
||||
public class GLModel {
|
||||
private long pointer;
|
||||
private MeshRaycaster raycaster;
|
||||
|
||||
public float hoverProgress;
|
||||
public boolean isHovering;
|
||||
|
||||
/* package */ GLModel(long ptr) {
|
||||
pointer = ptr;
|
||||
}
|
||||
|
||||
public GLModel() {
|
||||
this(Native.glmodel_create());
|
||||
}
|
||||
|
||||
public GLModel(Model model) {
|
||||
this(Native.glmodel_create());
|
||||
initFrom(model);
|
||||
}
|
||||
|
||||
public void initFrom(Model model) {
|
||||
Native.glmodel_init_from_model(pointer, model.pointer);
|
||||
}
|
||||
|
||||
public void initFrom(Model model, int i) {
|
||||
Native.glmodel_init_from_model_object(pointer, model.pointer, i);
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
Native.glmodel_set_color(pointer, Color.red(color) / (float) 0xFF, Color.green(color) / (float) 0xFF, Color.blue(color) / (float) 0xFF, Color.alpha(color) / (float) 0xFF);
|
||||
}
|
||||
|
||||
public void stilizedArrow(float tipRadius, float tipLength, float stemRadius, float stemLength) {
|
||||
Native.glmodel_stilized_arrow(pointer, tipRadius, tipLength, stemRadius, stemLength);
|
||||
}
|
||||
|
||||
public void initBackgroundTriangles() {
|
||||
Native.glmodel_init_background_triangles(pointer);
|
||||
}
|
||||
|
||||
public void initBoundingBox(Model model, int i) {
|
||||
Native.glmodel_init_bounding_box(pointer, model.pointer, i);
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return Native.glmodel_is_initialized(pointer);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return Native.glmodel_is_empty(pointer);
|
||||
}
|
||||
|
||||
public void render() {
|
||||
Native.glmodel_render(pointer);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
Native.glmodel_reset(pointer);
|
||||
raycaster = null;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
Native.glmodel_release(pointer);
|
||||
}
|
||||
|
||||
public MeshRaycaster getRaycaster() {
|
||||
if (raycaster == null) {
|
||||
Native.glmodel_init_raycast_data(pointer);
|
||||
raycaster = new MeshRaycaster();
|
||||
}
|
||||
return raycaster;
|
||||
}
|
||||
|
||||
public final class MeshRaycaster {
|
||||
public List<HitResult> raycast(GLRenderer renderer, ArrayList<HitResult> list, float x, float y) {
|
||||
assertTrue(renderer != null);
|
||||
list.clear();
|
||||
|
||||
Camera camera = renderer.getCamera();
|
||||
Vec3d point = Slic3rUtils.unproject(camera.getViewModelMatrix(), renderer.getProjectionMatrix(), renderer.getViewportWidth(), renderer.getViewportHeight(), x, y);
|
||||
Vec3d direction = camera.getDirForward().clone();
|
||||
if (!Prefs.isOrthoProjectionEnabled()) {
|
||||
direction = point.clone().add(camera.position.clone().negate()).normalize();
|
||||
}
|
||||
double[] v = Native.glmodel_raycast_closest_hit(pointer, point.asDoubleArray(), direction.asDoubleArray());
|
||||
list.ensureCapacity(v.length / 6);
|
||||
for (int i = 0; i < v.length; i += 6) {
|
||||
list.add(new HitResult(
|
||||
new Vec3d(v[i], v[i + 1], v[i + 2]),
|
||||
new Vec3d(v[i + 3], v[i + 4], v[i + 5])
|
||||
));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public static class HitResult {
|
||||
public final Vec3d position, normal;
|
||||
|
||||
public HitResult(Vec3d position, Vec3d normal) {
|
||||
this.position = position;
|
||||
this.normal = normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import static ru.ytkab0bp.slicebeam.utils.DebugUtils.assertTrue;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Color;
|
||||
import android.opengl.GLES30;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.SliceBeam;
|
||||
import ru.ytkab0bp.slicebeam.utils.IOUtils;
|
||||
|
||||
public class GLShaderProgram {
|
||||
final long pointer;
|
||||
private static ThreadLocal<FloatBuffer> matrixBuffer = new ThreadLocal<FloatBuffer>() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected FloatBuffer initialValue() {
|
||||
return ByteBuffer.allocateDirect(16 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
}
|
||||
};
|
||||
private static ThreadLocal<float[]> float16Buffer = new ThreadLocal<float[]>() {
|
||||
@Override
|
||||
protected float[] initialValue() {
|
||||
return new float[16];
|
||||
}
|
||||
};
|
||||
private static ThreadLocal<float[]> float12Buffer = new ThreadLocal<float[]>() {
|
||||
@Override
|
||||
protected float[] initialValue() {
|
||||
return new float[12];
|
||||
}
|
||||
};
|
||||
|
||||
public GLShaderProgram(String name) {
|
||||
AssetManager assets = SliceBeam.INSTANCE.getAssets();
|
||||
try {
|
||||
pointer = Native.shader_init_from_texts(name, IOUtils.readString(assets.open("shaders/" + name + ".fs")), IOUtils.readString(assets.open("shaders/" + name + ".vs")));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void startUsing() {
|
||||
Native.shader_start_using(pointer);
|
||||
}
|
||||
|
||||
public void stopUsing() {
|
||||
Native.shader_stop_using(pointer);
|
||||
}
|
||||
|
||||
public int getUniformLocation(String name) {
|
||||
// This function uses native uniform cache. Java one does not
|
||||
return Native.shader_get_uniform_location(pointer, name);
|
||||
}
|
||||
|
||||
public int getAttribLocation(String name) {
|
||||
// Same as getUniformLocation
|
||||
return Native.shader_get_attrib_location(pointer, name);
|
||||
}
|
||||
|
||||
public void setUniform(String name, boolean value) {
|
||||
GLES30.glUniform1i(getUniformLocation(name), value ? 1 : 0);
|
||||
}
|
||||
|
||||
public void setUniform(String name, float value) {
|
||||
GLES30.glUniform1f(getUniformLocation(name), value);
|
||||
}
|
||||
|
||||
public void setUniformMatrix3fv(String name, double[] value) {
|
||||
assertTrue(value.length == 12);
|
||||
|
||||
float[] floats = float12Buffer.get();
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
floats[i] = (float) value[i];
|
||||
}
|
||||
setUniformMatrix3fv(name, floats);
|
||||
}
|
||||
|
||||
public void setUniformMatrix3fv(String name, float[] value) {
|
||||
assertTrue(value.length == 12);
|
||||
|
||||
FloatBuffer buf = matrixBuffer.get();
|
||||
buf.position(0).limit(12);
|
||||
buf.put(value);
|
||||
buf.flip();
|
||||
GLES30.glUniformMatrix3fv(getUniformLocation(name), 1, false, buf);
|
||||
}
|
||||
|
||||
public void setUniformMatrix4fv(String name, double[] value) {
|
||||
assertTrue(value.length == 16);
|
||||
|
||||
float[] floats = float16Buffer.get();
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
floats[i] = (float) value[i];
|
||||
}
|
||||
setUniformMatrix4fv(name, floats);
|
||||
}
|
||||
|
||||
public void setUniformMatrix4fv(String name, float[] value) {
|
||||
assertTrue(value.length == 16);
|
||||
|
||||
FloatBuffer buf = matrixBuffer.get();
|
||||
buf.position(0).limit(16);
|
||||
buf.put(value);
|
||||
buf.flip();
|
||||
GLES30.glUniformMatrix4fv(getUniformLocation(name), 1, false, buf);
|
||||
}
|
||||
|
||||
public void setUniformColor(String name, int color) {
|
||||
setUniform4f(name, (float) Color.red(color) / 0xFF, (float) Color.green(color) / 0xFF, (float) Color.blue(color) / 0xFF, (float) Color.alpha(color) / 0xFF);
|
||||
}
|
||||
|
||||
public void setUniform4f(String name, float... value) {
|
||||
assertTrue(value.length == 4);
|
||||
|
||||
GLES30.glUniform4f(getUniformLocation(name), value[0], value[1], value[2], value[3]);
|
||||
}
|
||||
|
||||
public void setUniform3f(String name, float... value) {
|
||||
assertTrue(value.length == 3);
|
||||
|
||||
GLES30.glUniform3f(getUniformLocation(name), value[0], value[1], value[2]);
|
||||
}
|
||||
|
||||
public void setUniform2f(String name, float... value) {
|
||||
assertTrue(value.length == 2);
|
||||
|
||||
GLES30.glUniform2f(getUniformLocation(name), value[0], value[1]);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return Native.shader_get_id(pointer);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
Native.shader_release(pointer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import android.opengl.GLES30;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class GLShadersManager {
|
||||
public final static String
|
||||
SHADER_BACKGROUND = "background",
|
||||
SHADER_DASHED_LINES = "dashed_lines",
|
||||
SHADER_FLAT = "flat",
|
||||
SHADER_FLAT_CLIP = "flat_clip",
|
||||
SHADER_FLAT_TEXTURE = "flat_texture",
|
||||
SHADER_GOURAUD = "gouraud",
|
||||
SHADER_GOURAUD_LIGHT = "gouraud_light",
|
||||
SHADER_GOURAUD_LIGHT_INSTANCED = "gouraud_light_instanced",
|
||||
SHADER_IMGUI = "imgui",
|
||||
SHADER_MM_CONTOUR = "mm_contour",
|
||||
SHADER_MM_GOURAUD = "mm_gouraud",
|
||||
SHADER_PRINTBED = "printbed",
|
||||
SHADER_TOOLPATHS_COG = "toolpaths_cog",
|
||||
SHADER_VARIABLE_LAYER_HEIGHT = "variable_layer_height",
|
||||
SHADER_WIREFRAME = "wireframe",
|
||||
SHADER_BEAM_INTRO = "beam_intro";
|
||||
|
||||
@StringDef(value = {
|
||||
SHADER_BACKGROUND,
|
||||
SHADER_DASHED_LINES,
|
||||
SHADER_FLAT,
|
||||
SHADER_FLAT_CLIP,
|
||||
SHADER_FLAT_TEXTURE,
|
||||
SHADER_GOURAUD,
|
||||
SHADER_GOURAUD_LIGHT,
|
||||
SHADER_GOURAUD_LIGHT_INSTANCED,
|
||||
SHADER_IMGUI,
|
||||
SHADER_MM_CONTOUR,
|
||||
SHADER_MM_GOURAUD,
|
||||
SHADER_GOURAUD,
|
||||
SHADER_PRINTBED,
|
||||
SHADER_TOOLPATHS_COG,
|
||||
SHADER_VARIABLE_LAYER_HEIGHT,
|
||||
SHADER_WIREFRAME,
|
||||
SHADER_BEAM_INTRO
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ShaderType {}
|
||||
|
||||
private final static Map<String, GLShaderProgram> shaders = new HashMap<String, GLShaderProgram>() {
|
||||
@Override
|
||||
public GLShaderProgram get(@Nullable Object key) {
|
||||
GLShaderProgram shader = super.get(key);
|
||||
if (shader == null) put((String) key, shader = new GLShaderProgram((String) key));
|
||||
return shader;
|
||||
}
|
||||
};
|
||||
|
||||
public static void clearShaders() {
|
||||
for (GLShaderProgram program : shaders.values()) {
|
||||
program.release();
|
||||
}
|
||||
shaders.clear();
|
||||
}
|
||||
|
||||
public static GLShaderProgram get(@ShaderType String key) {
|
||||
return shaders.get(key);
|
||||
}
|
||||
|
||||
@Keep
|
||||
private static long getCurrentShaderPointer() {
|
||||
GLShaderProgram prog = getCurrentShader();
|
||||
return prog != null ? prog.pointer : 0;
|
||||
}
|
||||
|
||||
public static GLShaderProgram getCurrentShader() {
|
||||
int[] idRef = {0};
|
||||
GLES30.glGetIntegerv(GLES30.GL_CURRENT_PROGRAM, idRef, 0);
|
||||
int id = idRef[0];
|
||||
if (id != 0) {
|
||||
for (GLShaderProgram program : shaders.values()) {
|
||||
if (program.getId() == id) {
|
||||
return program;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.utils.Vec3d;
|
||||
|
||||
public class Model {
|
||||
public final String key = UUID.randomUUID().toString();
|
||||
final long pointer;
|
||||
|
||||
private double[] boundingExact;
|
||||
private double[] boundingApprox;
|
||||
|
||||
public Model() {
|
||||
this(Native.model_create());
|
||||
}
|
||||
|
||||
public Model(File f) throws Slic3rRuntimeError {
|
||||
this(f.getAbsolutePath());
|
||||
}
|
||||
|
||||
public Model(String path) throws Slic3rRuntimeError {
|
||||
this(Native.model_read_from_file(path, getBaseName(path)));
|
||||
}
|
||||
|
||||
private Model(long ptr) {
|
||||
this.pointer = ptr;
|
||||
}
|
||||
|
||||
private static String getBaseName(String path) {
|
||||
if (path.contains("/")) {
|
||||
path = path.substring(path.lastIndexOf('/') + 1);
|
||||
}
|
||||
if (path.contains(".")) {
|
||||
path = path.substring(0, path.lastIndexOf('.'));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public void getBoundingBoxExact(int i, Vec3d min, Vec3d max) {
|
||||
double[] data = Native.model_get_bounding_box_exact(pointer, i);
|
||||
min.set(data[0], data[1], data[2]);
|
||||
max.set(data[3], data[4], data[5]);
|
||||
}
|
||||
|
||||
public void getBoundingBoxApprox(int i, Vec3d min, Vec3d max) {
|
||||
double[] data = Native.model_get_bounding_box_approx(pointer, i);
|
||||
min.set(data[0], data[1], data[2]);
|
||||
max.set(data[3], data[4], data[5]);
|
||||
}
|
||||
|
||||
public Vec3d getBoundingBoxExactMin() {
|
||||
if (boundingExact == null) boundingExact = Native.model_get_bounding_box_exact_global(pointer);
|
||||
return new Vec3d(boundingExact[0], boundingExact[1], boundingExact[2]);
|
||||
}
|
||||
|
||||
public Vec3d getBoundingBoxExactMax() {
|
||||
if (boundingExact == null) boundingExact = Native.model_get_bounding_box_exact_global(pointer);
|
||||
return new Vec3d(boundingExact[3], boundingExact[4], boundingExact[5]);
|
||||
}
|
||||
|
||||
public Vec3d getBoundingBoxApproxMin() {
|
||||
if (boundingApprox == null) boundingApprox = Native.model_get_bounding_box_approx_global(pointer);
|
||||
return new Vec3d(boundingApprox[0], boundingApprox[1], boundingApprox[2]);
|
||||
}
|
||||
|
||||
public Vec3d getBoundingBoxApproxMax() {
|
||||
if (boundingApprox == null) boundingApprox = Native.model_get_bounding_box_approx_global(pointer);
|
||||
return new Vec3d(boundingApprox[3], boundingApprox[4], boundingApprox[5]);
|
||||
}
|
||||
|
||||
public void resetBoundingBox() {
|
||||
boundingExact = null;
|
||||
boundingApprox = null;
|
||||
}
|
||||
|
||||
public void translate(int i, double x, double y, double z) {
|
||||
Native.model_translate(pointer, i, x, y, z);
|
||||
}
|
||||
|
||||
public void translate(double x, double y, double z) {
|
||||
Native.model_translate_global(pointer, x, y, z);
|
||||
resetBoundingBox();
|
||||
}
|
||||
|
||||
public void scale(int i, double x, double y, double z) {
|
||||
Native.model_scale(pointer, i, x, y, z);
|
||||
}
|
||||
|
||||
public void rotate(int i, double x, double y, double z) {
|
||||
Native.model_rotate(pointer, i, x, y, z);
|
||||
}
|
||||
|
||||
public int getObjectsCount() {
|
||||
return Native.model_get_objects_count(pointer);
|
||||
}
|
||||
|
||||
public void addObject(Model from, int i) {
|
||||
Native.model_add_object_from_another(pointer, from.pointer, i);
|
||||
}
|
||||
|
||||
public void deleteObject(int i) {
|
||||
Native.model_delete_object(pointer, i);
|
||||
}
|
||||
|
||||
public void getTranslation(int i, Vec3d vec) {
|
||||
double[] tr = Native.model_get_translation(pointer, i);
|
||||
vec.set(tr[0], tr[1], tr[2]);
|
||||
}
|
||||
|
||||
public void getRotation(int i, Vec3d vec) {
|
||||
double[] tr = Native.model_get_rotation(pointer, i);
|
||||
vec.set(tr[0], tr[1], tr[2]);
|
||||
}
|
||||
|
||||
public boolean isLeftHanded(int i) {
|
||||
return Native.model_is_left_handed(pointer, i);
|
||||
}
|
||||
|
||||
public void getScale(int i, Vec3d vec) {
|
||||
double[] tr = Native.model_get_scale(pointer, i);
|
||||
vec.set(tr[0], tr[1], tr[2]);
|
||||
}
|
||||
|
||||
public void getMirror(int i, Vec3d vec) {
|
||||
double[] tr = Native.model_get_mirror(pointer, i);
|
||||
vec.set(tr[0], tr[1], tr[2]);
|
||||
}
|
||||
|
||||
public GCodeProcessorResult slice(String configPath, String gcodePath, SliceListener listener) throws Slic3rRuntimeError {
|
||||
return new GCodeProcessorResult(Native.model_slice(pointer, configPath, gcodePath, listener));
|
||||
}
|
||||
|
||||
public void release() {
|
||||
Native.model_release(pointer);
|
||||
}
|
||||
|
||||
public static Model merge(Model... models) {
|
||||
long[] ptrs = new long[models.length];
|
||||
for (int i = 0, modelsSize = models.length; i < modelsSize; i++) {
|
||||
Model m = models[i];
|
||||
ptrs[i] = m.pointer;
|
||||
}
|
||||
return new Model(Native.models_merge(ptrs));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.SliceBeam;
|
||||
|
||||
class Native {
|
||||
static {
|
||||
System.loadLibrary("c++_shared");
|
||||
System.loadLibrary("gmp");
|
||||
System.loadLibrary("gmpxx");
|
||||
System.loadLibrary("mpfr");
|
||||
OCCTLoader.load();
|
||||
|
||||
System.loadLibrary("slic3r");
|
||||
|
||||
set_svg_path_prefix(SliceBeam.INSTANCE.getCacheDir().getAbsolutePath());
|
||||
}
|
||||
|
||||
static native void get_print_config_def(PrintConfigDef def);
|
||||
|
||||
static native void set_svg_path_prefix(String prefix);
|
||||
|
||||
static native long shader_init_from_texts(String name, String fragment, String vertex);
|
||||
static native int shader_get_id(long ptr);
|
||||
static native int shader_get_uniform_location(long ptr, String name);
|
||||
static native int shader_get_attrib_location(long ptr, String name);
|
||||
static native void shader_start_using(long ptr);
|
||||
static native void shader_stop_using(long ptr);
|
||||
static native void shader_release(long ptr);
|
||||
|
||||
static native long glmodel_create();
|
||||
static native void glmodel_init_from_model(long ptr, long model);
|
||||
static native void glmodel_init_from_model_object(long ptr, long model, int i);
|
||||
static native void glmodel_init_raycast_data(long ptr);
|
||||
static native void glmodel_set_color(long ptr, float red, float green, float blue, float alpha);
|
||||
static native void glmodel_render(long ptr);
|
||||
static native void glmodel_stilized_arrow(long ptr, float tipRadius, float tipLength, float stemRadius, float stemLength);
|
||||
static native void glmodel_init_background_triangles(long ptr);
|
||||
static native void glmodel_init_bounding_box(long ptr, long modelPtr, int i);
|
||||
static native boolean glmodel_is_initialized(long ptr);
|
||||
static native boolean glmodel_is_empty(long ptr);
|
||||
static native double[] glmodel_raycast_closest_hit(long ptr, double[] point, double[] direction);
|
||||
static native void glmodel_reset(long ptr);
|
||||
static native void glmodel_release(long ptr);
|
||||
|
||||
static native long bed_create(long[] data);
|
||||
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 boolean bed_arrange(long ptr, long modelPtr);
|
||||
static native void bed_release(long ptr);
|
||||
|
||||
static native long models_merge(long... ptrs);
|
||||
static native long model_create();
|
||||
static native long model_read_from_file(String path, String baseName) throws Slic3rRuntimeError;
|
||||
static native int model_get_objects_count(long ptr);
|
||||
static native void model_add_object_from_another(long ptr, long from, int i);
|
||||
static native void model_delete_object(long ptr, int i);
|
||||
static native double[] model_get_translation(long ptr, int objectIndex);
|
||||
static native double[] model_get_scale(long ptr, int objectIndex);
|
||||
static native double[] model_get_mirror(long ptr, int objectIndex);
|
||||
static native double[] model_get_rotation(long ptr, int objectIndex);
|
||||
static native double[] model_get_bounding_box_exact(long ptr, int i);
|
||||
static native double[] model_get_bounding_box_approx(long ptr, int i);
|
||||
static native double[] model_get_bounding_box_exact_global(long ptr);
|
||||
static native double[] model_get_bounding_box_approx_global(long ptr);
|
||||
static native boolean model_is_left_handed(long ptr, int i);
|
||||
static native void model_translate(long ptr, int i, double x, double y, double z);
|
||||
static native void model_translate_global(long ptr, double x, double y, double z);
|
||||
static native void model_scale(long ptr, int i, double x, double y, double z);
|
||||
static native void model_rotate(long ptr, int i, double x, double y, double z);
|
||||
static native long model_slice(long ptr, String configPath, String path, SliceListener listener) throws Slic3rRuntimeError;
|
||||
static native void model_release(long ptr);
|
||||
|
||||
static native long gcoderesult_load_file(String path, String name);
|
||||
static native String gcoderesult_get_recommended_name(long ptr);
|
||||
static native void gcoderesult_release(long ptr);
|
||||
|
||||
static native long vgcode_create();
|
||||
static native void vgcode_init(long ptr);
|
||||
static native boolean vgcode_is_initialized(long ptr);
|
||||
static native void vgcode_set_colors(long ptr, int[] colors);
|
||||
static native long vgcode_get_layers_count(long ptr);
|
||||
static native void vgcode_load(long ptr, long resultPtr);
|
||||
static native void vgcode_render(long ptr, float[] viewMatrix, float[] projectionMatrix);
|
||||
static native void vgcode_set_layers_view_range(long ptr, long min, long max);
|
||||
static native long[] vgcode_get_layers_view_range(long ptr);
|
||||
static native void vgcode_reset(long ptr);
|
||||
static native void vgcode_release(long ptr);
|
||||
|
||||
static native long utils_config_create(String config);
|
||||
static native boolean utils_config_check_compatibility(long ptr, String condition);
|
||||
static native String utils_config_eval(long ptr, String condition) throws Slic3rRuntimeError;
|
||||
static native void utils_config_release(long ptr);
|
||||
|
||||
static native void utils_calc_view_normal_matrix(double[] viewMatrix, double[] worldMatrix, double[] normalMatrix);
|
||||
static native double[] utils_unproject(double[] viewMatrix, double[] projectionMatrix, int screenWidth, int screenHeight, double x, double y);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
class OCCTLoader {
|
||||
private final static List<String> LIBS = Arrays.asList(
|
||||
"TKDESTEP",
|
||||
"TKXCAF",
|
||||
"TKLCAF",
|
||||
"TKCAF",
|
||||
"TKCDF",
|
||||
"TKV3d",
|
||||
"TKMesh",
|
||||
"TKXMesh",
|
||||
"TKBO",
|
||||
"TKPrim",
|
||||
"TKHLR",
|
||||
"TKShHealing",
|
||||
"TKTopAlgo",
|
||||
"TKGeomAlgo",
|
||||
"TKGeomBase",
|
||||
"TKBRep",
|
||||
"TKG3d",
|
||||
"TKG2d",
|
||||
"TKMath",
|
||||
"TKernel",
|
||||
"TKDE"
|
||||
);
|
||||
|
||||
static void load() {
|
||||
for (String lib : LIBS) {
|
||||
System.loadLibrary(lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PrintConfigDef {
|
||||
public static List<String> SKIP_DEFAULT_OPTIONS = Arrays.asList(
|
||||
"tilt_up_initial_speed",
|
||||
"tilt_up_finish_speed",
|
||||
"tilt_down_initial_speed",
|
||||
"tilt_down_finish_speed",
|
||||
"tower_speed"
|
||||
);
|
||||
|
||||
private static PrintConfigDef instance;
|
||||
|
||||
private final static Map<String, Class<?>> clzMap = new HashMap<String, Class<?>>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Class<?> get(@Nullable Object key) {
|
||||
Class<?> clz = super.get(key);
|
||||
if (clz == null) {
|
||||
try {
|
||||
put((String) key, clz = Class.forName((String) key));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return clz;
|
||||
}
|
||||
};
|
||||
private final static Map<Pair<Class<?>, String>, Field> fieldMap = new HashMap<Pair<Class<?>, String>, Field>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Field get(@Nullable Object key) {
|
||||
Field f = super.get(key);
|
||||
if (f == null) {
|
||||
Pair<Class<?>, String> k = (Pair<Class<?>, String>) key;
|
||||
try {
|
||||
f = k.first.getDeclaredField(k.second);
|
||||
f.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
};
|
||||
private final static Map<Pair<Class<?>, String>, Object> valueMap = new HashMap<>();
|
||||
|
||||
public Map<String, ConfigOptionDef> options = new HashMap<>();
|
||||
|
||||
@Keep
|
||||
PrintConfigDef() {}
|
||||
|
||||
@Keep
|
||||
static Object resolveEnum(String className, String value) {
|
||||
className = className.replace("/", ".");
|
||||
Class<?> clz = clzMap.get(className);
|
||||
Pair<Class<?>, String> key = new Pair<>(clz, value);
|
||||
Object val = valueMap.get(key);
|
||||
if (val != null) return val;
|
||||
|
||||
Field f = fieldMap.get(key);
|
||||
try {
|
||||
valueMap.put(key, val = f.get(null));
|
||||
return val;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static PrintConfigDef getInstance() {
|
||||
if (instance == null) {
|
||||
Native.get_print_config_def(instance = new PrintConfigDef());
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Keep
|
||||
void addOption(String key, ConfigOptionDef def) {
|
||||
options.put(key, def);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.BuildConfig;
|
||||
import ru.ytkab0bp.slicebeam.config.ConfigObject;
|
||||
|
||||
public class Slic3rConfigWrapper {
|
||||
public final static String BLACKLISTED_SYMBOLS = "<>[]:/\\|?*\"";
|
||||
|
||||
public final static List<String> PRINT_CONFIG_KEYS = Arrays.asList(
|
||||
"layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "slicing_mode",
|
||||
"top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness",
|
||||
"extra_perimeters", "extra_perimeters_on_overhangs", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs",
|
||||
"seam_position","staggered_inner_seams", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
|
||||
"infill_every_layers", /*"infill_only_where_needed",*/ "solid_infill_every_layers", "fill_angle", "bridge_angle",
|
||||
"solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first",
|
||||
"ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing",
|
||||
"max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour",
|
||||
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist",
|
||||
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed",
|
||||
"enable_dynamic_overhang_speeds", "overhang_speed_0", "overhang_speed_1", "overhang_speed_2", "overhang_speed_3",
|
||||
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
|
||||
"bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration",
|
||||
"external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration", "travel_acceleration", "wipe_tower_acceleration",
|
||||
"bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
|
||||
"min_skirt_length", "brim_width", "brim_separation", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
|
||||
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
|
||||
"support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_closing_radius", "support_material_style",
|
||||
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers",
|
||||
"support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops",
|
||||
"support_material_contact_distance", "support_material_bottom_contact_distance",
|
||||
"support_material_buildplate_only",
|
||||
"support_tree_angle", "support_tree_angle_slow", "support_tree_branch_diameter", "support_tree_branch_diameter_angle", "support_tree_branch_diameter_double_wall",
|
||||
"support_tree_top_rate", "support_tree_branch_distance", "support_tree_tip_diameter",
|
||||
"dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius",
|
||||
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "gcode_substitutions", "perimeter_extruder",
|
||||
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
|
||||
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
|
||||
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
||||
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio",
|
||||
"elefant_foot_compensation", "xy_size_compensation", "resolution", "gcode_resolution", "arc_fitting",
|
||||
"wipe_tower", "wipe_tower_x", "wipe_tower_y",
|
||||
"wipe_tower_width", "wipe_tower_cone_angle", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width",
|
||||
"mmu_segmented_region_interlocking_depth", "wipe_tower_extruder", "wipe_tower_no_sparse_layers", "wipe_tower_extra_flow", "wipe_tower_extra_spacing", "compatible_printers", "compatible_printers_condition", "inherits",
|
||||
"perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
|
||||
"wall_distribution_count", "min_feature_size", "min_bead_width",
|
||||
"top_one_perimeter_type", "only_one_perimeter_first_layer"
|
||||
);
|
||||
public final static List<String> FILAMENT_CONFIG_KEYS = Arrays.asList(
|
||||
"filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed", "filament_infill_max_speed", "filament_infill_max_crossing_speed",
|
||||
"extrusion_multiplier", "filament_density", "filament_cost", "filament_spool_weight", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time",
|
||||
"filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", "filament_stamping_loading_speed", "filament_stamping_distance",
|
||||
"filament_cooling_initial_speed", "filament_purge_multiplier", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower",
|
||||
"filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow",
|
||||
"temperature", "idle_temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed",
|
||||
"max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed",
|
||||
"start_filament_gcode", "end_filament_gcode", "enable_dynamic_fan_speeds", "chamber_temperature", "chamber_minimal_temperature",
|
||||
"overhang_fan_speed_0", "overhang_fan_speed_1", "overhang_fan_speed_2", "overhang_fan_speed_3",
|
||||
// Retract overrides
|
||||
"filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",
|
||||
"filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe", "filament_retract_length_toolchange", "filament_retract_restart_extra_toolchange", "filament_travel_ramping_lift",
|
||||
"filament_travel_slope", "filament_travel_max_lift", "filament_travel_lift_before_obstacle",
|
||||
// Profile compatibility
|
||||
"filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits",
|
||||
// Shrinkage compensation
|
||||
"filament_shrinkage_compensation_xy", "filament_shrinkage_compensation_z"
|
||||
);
|
||||
public final static List<String> PRINTER_CONFIG_KEYS = Arrays.asList(
|
||||
"printer_technology", "autoemit_temperature_commands",
|
||||
"bed_shape", "bed_custom_texture", "bed_custom_model", "binary_gcode", "z_offset", "gcode_flavor", "use_relative_e_distances",
|
||||
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height", "prefer_clockwise_movements",
|
||||
//FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset.
|
||||
"host_type", "print_host", "printhost_apikey", "printhost_cafile",
|
||||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||
"color_change_gcode", "pause_print_gcode", "template_custom_gcode",
|
||||
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
|
||||
"cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "multimaterial_purging",
|
||||
"max_print_height", "default_print_profile", "inherits",
|
||||
"remaining_times", "silent_mode",
|
||||
"machine_limits_usage", "thumbnails", "thumbnails_format",
|
||||
"machine_max_acceleration_extruding", "machine_max_acceleration_retracting", "machine_max_acceleration_travel",
|
||||
"machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
|
||||
"machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
|
||||
"machine_min_extruding_rate", "machine_min_travel_rate",
|
||||
"machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e"
|
||||
);
|
||||
public final static List<String> PHYSICAL_PRINTER_CONFIG_KEYS = Arrays.asList(
|
||||
"preset_name", // temporary option to compatibility with older Slicer
|
||||
"preset_names",
|
||||
"printer_technology",
|
||||
"host_type",
|
||||
"print_host",
|
||||
"printhost_apikey",
|
||||
"printhost_cafile",
|
||||
"printhost_port",
|
||||
"printhost_authorization_type",
|
||||
// HTTP digest authentization (RFC 2617)
|
||||
"printhost_user",
|
||||
"printhost_password",
|
||||
"printhost_ssl_ignore_revoke"
|
||||
);
|
||||
|
||||
private File file;
|
||||
|
||||
public List<ConfigObject> printConfigs = new ArrayList<>();
|
||||
public List<ConfigObject> printerConfigs = new ArrayList<>();
|
||||
public List<ConfigObject> filamentConfigs = new ArrayList<>();
|
||||
public List<ConfigObject> physicalPrintersConfigs = new ArrayList<>();
|
||||
|
||||
public List<ConfigObject> printerModels = new ArrayList<>();
|
||||
public ConfigObject presets;
|
||||
public ConfigObject vendor;
|
||||
|
||||
public Slic3rConfigWrapper() {}
|
||||
|
||||
public Slic3rConfigWrapper(File f) throws IOException {
|
||||
file = f;
|
||||
readFromStream(new FileInputStream(file));
|
||||
}
|
||||
|
||||
public Slic3rConfigWrapper(InputStream in) throws IOException {
|
||||
readFromStream(in);
|
||||
}
|
||||
|
||||
public void importPrint(ConfigObject obj) {
|
||||
importInto(printConfigs, obj);
|
||||
}
|
||||
|
||||
public void importPrinter(ConfigObject obj) {
|
||||
importInto(printerConfigs, obj);
|
||||
}
|
||||
|
||||
public void importFilament(ConfigObject obj) {
|
||||
importInto(filamentConfigs, obj);
|
||||
}
|
||||
|
||||
public void importInto(List<ConfigObject> list, ConfigObject obj) {
|
||||
for (ConfigObject o : list) {
|
||||
if (o.getTitle().equals(obj.getTitle())) {
|
||||
o.values.clear();
|
||||
o.values.putAll(obj.values);
|
||||
return;
|
||||
}
|
||||
}
|
||||
list.add(obj);
|
||||
}
|
||||
|
||||
public ConfigObject findFilament(String key) {
|
||||
for (ConfigObject obj : filamentConfigs) {
|
||||
if (key.equals(obj.getTitle())) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ConfigObject findPrinterVariant(String model, String variant) {
|
||||
for (ConfigObject obj : printerConfigs) {
|
||||
if (model.equals(obj.get("printer_model")) && variant.equals(obj.get("printer_variant"))) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ConfigObject findPrint(String key) {
|
||||
for (ConfigObject obj : printConfigs) {
|
||||
if (key.equals(obj.getTitle())) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ConfigObject findPrinter(String key) {
|
||||
for (ConfigObject obj : printerConfigs) {
|
||||
if (key.equals(obj.getTitle())) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void serializeList(StringBuilder sb, String key, List<ConfigObject> list) {
|
||||
for (ConfigObject cfg : list) {
|
||||
sb.append("[").append(key).append(":").append(cfg.getTitle()).append("]\n");
|
||||
|
||||
for (Map.Entry<String, String> en : cfg.values.entrySet()) {
|
||||
sb.append(en.getKey()).append(" = ").append(en.getValue().replace("\n", "\\n")).append("\n");
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
public String serialize() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("# generated by Slice Beam ").append(BuildConfig.VERSION_NAME).append("\n\n");
|
||||
serializeList(sb, "printer", printerConfigs);
|
||||
serializeList(sb, "print", printConfigs);
|
||||
serializeList(sb, "filament", filamentConfigs);
|
||||
|
||||
if (presets != null) {
|
||||
sb.append("[presets]\n");
|
||||
for (Map.Entry<String, String> en : presets.values.entrySet()) {
|
||||
sb.append(en.getKey()).append(" = ").append(en.getValue().replace("\n", "\\n")).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void readFromStream(InputStream in) throws IOException {
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(in));
|
||||
|
||||
ConfigObject currentPrintConfig = null;
|
||||
ConfigObject currentPrinterConfig = null;
|
||||
ConfigObject currentFilamentConfig = null;
|
||||
ConfigObject currentPhysicalPrinterConfig = null;
|
||||
|
||||
ConfigObject explicitObject = null;
|
||||
|
||||
Map<String, ConfigObject> parentMap = new HashMap<>();
|
||||
|
||||
String line;
|
||||
while ((line = r.readLine()) != null) {
|
||||
if (line.startsWith("#")) continue;
|
||||
|
||||
if (line.startsWith("[") && line.endsWith("]")) {
|
||||
if (line.equals("[obsolete_presets]")) {
|
||||
explicitObject = new ConfigObject();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!line.contains(":") && !line.equals("[presets]") && !line.equals("[vendor]")) {
|
||||
throw new UnsupportedEncodingException(String.format("Failed to decode config category: %s", line));
|
||||
}
|
||||
if (currentPrintConfig != null || currentPrinterConfig != null || currentFilamentConfig != null || currentPhysicalPrinterConfig != null) {
|
||||
throw new UnsupportedEncodingException("Failed to decode config: explicit category in combined profile!");
|
||||
}
|
||||
|
||||
if (line.equals("[presets]")) {
|
||||
explicitObject = presets = new ConfigObject();
|
||||
continue;
|
||||
}
|
||||
if (line.equals("[vendor]")) {
|
||||
explicitObject = vendor = new ConfigObject();
|
||||
continue;
|
||||
}
|
||||
|
||||
line = line.substring(1, line.length() - 1);
|
||||
String[] spl = line.split(":");
|
||||
String key = spl[0];
|
||||
String name = spl[1];
|
||||
|
||||
switch (key) {
|
||||
case "printer_model": {
|
||||
printerModels.add(explicitObject = new ConfigObject(name));
|
||||
break;
|
||||
}
|
||||
case "print": {
|
||||
printConfigs.add(explicitObject = new ConfigObject(name));
|
||||
explicitObject.profileListType = ConfigObject.PROFILE_LIST_PRINT;
|
||||
break;
|
||||
}
|
||||
case "printer": {
|
||||
printerConfigs.add(explicitObject = new ConfigObject(name));
|
||||
explicitObject.profileListType = ConfigObject.PROFILE_LIST_PRINTER;
|
||||
break;
|
||||
}
|
||||
case "physical_printer": {
|
||||
physicalPrintersConfigs.add(explicitObject = new ConfigObject(name));
|
||||
break;
|
||||
}
|
||||
case "filament": {
|
||||
filamentConfigs.add(explicitObject = new ConfigObject(name));
|
||||
explicitObject.profileListType = ConfigObject.PROFILE_LIST_FILAMENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parentMap.put(name, explicitObject);
|
||||
}
|
||||
|
||||
int i = line.indexOf(" = ");
|
||||
if (i != -1) {
|
||||
String key = line.substring(0, i);
|
||||
String value = line.substring(i + 3).trim().replace("\\n", "\n");
|
||||
|
||||
if (key.equals("ironing_type") && value.equals("no ironing")) {
|
||||
value = "top";
|
||||
}
|
||||
if (key.equals("thumbnails")) {
|
||||
value = value.replaceAll(", \\d+x\\d+/COLPIC", "");
|
||||
}
|
||||
|
||||
if (explicitObject != null) {
|
||||
explicitObject.put(key, value);
|
||||
} else {
|
||||
if (key.equals("printer_settings_id")) {
|
||||
if (currentPrinterConfig == null)
|
||||
currentPrinterConfig = new ConfigObject();
|
||||
currentPrinterConfig.setTitle(value);
|
||||
}
|
||||
if (key.equals("print_settings_id")) {
|
||||
if (currentPrintConfig == null)
|
||||
currentPrintConfig = new ConfigObject();
|
||||
currentPrintConfig.setTitle(value);
|
||||
}
|
||||
if (key.equals("filament_settings_id")) {
|
||||
if (currentFilamentConfig == null)
|
||||
currentFilamentConfig = new ConfigObject();
|
||||
currentFilamentConfig.setTitle(value);
|
||||
}
|
||||
|
||||
if (PRINT_CONFIG_KEYS.contains(key)) {
|
||||
if (currentPrintConfig == null)
|
||||
currentPrintConfig = new ConfigObject();
|
||||
currentPrintConfig.put(key, value);
|
||||
}
|
||||
if (FILAMENT_CONFIG_KEYS.contains(key)) {
|
||||
if (currentFilamentConfig == null)
|
||||
currentFilamentConfig = new ConfigObject();
|
||||
currentFilamentConfig.put(key, value);
|
||||
}
|
||||
if (PRINTER_CONFIG_KEYS.contains(key)) {
|
||||
if (currentPrinterConfig == null)
|
||||
currentPrinterConfig = new ConfigObject();
|
||||
currentPrinterConfig.put(key, value);
|
||||
}
|
||||
if (PHYSICAL_PRINTER_CONFIG_KEYS.contains(key)) {
|
||||
if (currentPhysicalPrinterConfig == null)
|
||||
currentPhysicalPrinterConfig = new ConfigObject();
|
||||
currentPhysicalPrinterConfig.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ConfigObject obj : parentMap.values()) {
|
||||
while (obj.values.containsKey("inherits")) {
|
||||
String value = obj.values.remove("inherits");
|
||||
if (value.isEmpty()) continue;
|
||||
|
||||
if (value.contains(";")) {
|
||||
String[] spl = value.split(";");
|
||||
|
||||
for (String s : spl) {
|
||||
String str = s.trim();
|
||||
Map<String, String> newValues = new HashMap<>();
|
||||
newValues.putAll(parentMap.get(str).values);
|
||||
newValues.putAll(obj.values);
|
||||
obj.values = newValues;
|
||||
}
|
||||
} else {
|
||||
if (parentMap.containsKey(value)) {
|
||||
Map<String, String> newValues = new HashMap<>();
|
||||
newValues.putAll(parentMap.get(value).values);
|
||||
newValues.putAll(obj.values);
|
||||
obj.values = newValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPrintConfig != null) {
|
||||
printConfigs.add(currentPrintConfig);
|
||||
}
|
||||
if (currentPrinterConfig != null) {
|
||||
printerConfigs.add(currentPrinterConfig);
|
||||
}
|
||||
if (currentFilamentConfig != null) {
|
||||
filamentConfigs.add(currentFilamentConfig);
|
||||
}
|
||||
if (currentPhysicalPrinterConfig != null) {
|
||||
physicalPrintersConfigs.add(currentPhysicalPrinterConfig);
|
||||
}
|
||||
|
||||
if (presets == null) {
|
||||
presets = new ConfigObject();
|
||||
if (currentPrintConfig != null) {
|
||||
presets.put("print", currentPrintConfig.getTitle());
|
||||
}
|
||||
if (currentFilamentConfig != null) {
|
||||
presets.put("filament", currentFilamentConfig.getTitle());
|
||||
}
|
||||
if (currentPrinterConfig != null) {
|
||||
presets.put("printer", currentPrinterConfig.getTitle());
|
||||
}
|
||||
if (currentPhysicalPrinterConfig != null) {
|
||||
presets.put("physical_printer", currentPhysicalPrinterConfig.getTitle());
|
||||
}
|
||||
}
|
||||
|
||||
r.close();
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.SliceBeam;
|
||||
|
||||
public class Slic3rLocalization {
|
||||
private static Map<String, Slic3rLocalization> localesMap = new HashMap<String, Slic3rLocalization>() {
|
||||
@Override
|
||||
public Slic3rLocalization get(@Nullable Object key) {
|
||||
Slic3rLocalization locale = super.get(key);
|
||||
if (locale == null) {
|
||||
try {
|
||||
put((String) key, locale = new Slic3rLocalization((String) key));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
put((String) key, locale = new Slic3rLocalization("en"));
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
};
|
||||
|
||||
private Map<String, String> map = new HashMap<>();
|
||||
|
||||
public Slic3rLocalization(String key) throws IOException {
|
||||
InputStream in = SliceBeam.INSTANCE.getAssets().open("localization/" + key + ".po");
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(in));
|
||||
String line;
|
||||
StringBuilder msgId = null;
|
||||
StringBuilder msgStr = null;
|
||||
while ((line = r.readLine()) != null) {
|
||||
if (line.startsWith("#")) continue;
|
||||
|
||||
if (line.startsWith("msgid")) {
|
||||
msgId = new StringBuilder(line.substring(7, line.length() - 1));
|
||||
} else if (line.startsWith("msgstr")) {
|
||||
msgStr = new StringBuilder(line.substring(8, line.length() - 1));
|
||||
} else if (line.isEmpty()) {
|
||||
if (!TextUtils.isEmpty(msgId) && !TextUtils.isEmpty(msgStr)) {
|
||||
// This hack allows us to maintain vanilla strings in native code while using our app name at the same time
|
||||
map.put(msgId.toString(), replaceStr(msgStr.toString()));
|
||||
}
|
||||
|
||||
msgId = null;
|
||||
msgStr = null;
|
||||
} else if (line.startsWith("\"") && line.endsWith("\"")) {
|
||||
if (msgStr != null) {
|
||||
msgStr.append(line.substring(1, line.length() - 1));
|
||||
} else if (msgId != null) {
|
||||
msgId.append(line.substring(1, line.length() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
r.close();
|
||||
in.close();
|
||||
}
|
||||
|
||||
private static String replaceStr(String val) {
|
||||
return val.replace("\\n", "\n").replaceAll("\\\\(.)", "$1").replace("Slic3r", "Slice Beam").replace("PrusaSlicer", "Slice Beam");
|
||||
}
|
||||
|
||||
public static String getString(String key) {
|
||||
return getInstance().get(key);
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
String val = map.get(key);
|
||||
if (TextUtils.isEmpty(val)) {
|
||||
map.put(key, val = replaceStr(key));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public static Slic3rLocalization getInstance(String key) {
|
||||
return localesMap.get(key);
|
||||
}
|
||||
|
||||
public static Slic3rLocalization getInstance() {
|
||||
return getInstance(Locale.getDefault().getLanguage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
public class Slic3rRuntimeError extends Exception {
|
||||
public Slic3rRuntimeError() {
|
||||
}
|
||||
|
||||
public Slic3rRuntimeError(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public Slic3rRuntimeError(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public Slic3rRuntimeError(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import static ru.ytkab0bp.slicebeam.utils.DebugUtils.assertTrue;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.utils.Vec3d;
|
||||
|
||||
public class Slic3rUtils {
|
||||
public static void calcViewNormalMatrix(double[] viewMatrix, double[] worldMatrix, double[] normalMatrix) {
|
||||
assertTrue(viewMatrix.length == 16);
|
||||
assertTrue(worldMatrix.length == 16);
|
||||
assertTrue(normalMatrix.length == 12);
|
||||
|
||||
Native.utils_calc_view_normal_matrix(viewMatrix, worldMatrix, normalMatrix);
|
||||
}
|
||||
|
||||
public static Vec3d unproject(double[] viewMatrix, double[] projectionMatrix, int screenWidth, int screenHeight, double x, double y) {
|
||||
assertTrue(viewMatrix.length == 16);
|
||||
assertTrue(projectionMatrix.length == 16);
|
||||
|
||||
double[] v = Native.utils_unproject(viewMatrix, projectionMatrix, screenWidth, screenHeight, x, y);
|
||||
return new Vec3d(v[0], v[1], v[2]);
|
||||
}
|
||||
|
||||
public final static class ConfigChecker {
|
||||
private final long pointer;
|
||||
|
||||
public ConfigChecker(String config) {
|
||||
pointer = Native.utils_config_create(config);
|
||||
}
|
||||
|
||||
public boolean checkCompatibility(String condition) {
|
||||
if (TextUtils.isEmpty(condition)) return true;
|
||||
return Native.utils_config_check_compatibility(pointer, condition);
|
||||
}
|
||||
|
||||
public String eval(String condition) throws Slic3rRuntimeError {
|
||||
return Native.utils_config_eval(pointer, condition);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
Native.utils_config_release(pointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
public interface SliceListener {
|
||||
void onProgress(int progress, String text);
|
||||
}
|
||||
Reference in New Issue
Block a user