mirror of
https://github.com/Dark98/SliceBeam.git
synced 2026-07-03 00:38:53 +00:00
Compare commits
4 Commits
master
...
gh-actions
| Author | SHA1 | Date | |
|---|---|---|---|
| c584dd6324 | |||
| 261ba81e06 | |||
| 6dbb3a8f1d | |||
| 76996225df |
@@ -0,0 +1,28 @@
|
||||
name: Android CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
cache: gradle
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
|
||||
- name: Upload a Debug APK
|
||||
uses: actions/upload-artifact@v6.0.0
|
||||
with:
|
||||
path: app/build/outputs/apk/debug/*.apk
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"java.configuration.updateBuildConfiguration": "automatic",
|
||||
"java.jdt.ls.java.home": "C:\\Program Files\\Android\\Android Studio\\jbr",
|
||||
"java.configuration.runtimes": [
|
||||
{
|
||||
"name": "JavaSE-21",
|
||||
"path": "C:\\Program Files\\Android\\Android Studio\\jbr",
|
||||
"default": true
|
||||
}
|
||||
],
|
||||
"terminal.integrated.env.windows": {
|
||||
"JAVA_HOME": "C:\\Program Files\\Android\\Android Studio\\jbr",
|
||||
"PATH": "C:\\Program Files\\Android\\Android Studio\\jbr\\bin;${env:PATH}"
|
||||
}
|
||||
}
|
||||
+3
-6
@@ -22,7 +22,7 @@ add_compile_options(-fsigned-char)
|
||||
# Suppress all warnings
|
||||
add_definitions(-w)
|
||||
add_definitions(-DNDEBUG)
|
||||
add_definitions(-DSLIC3R_VERSION=${SLIC3R_VERSION})
|
||||
add_definitions(-DSLIC3R_VERSION="${SLIC3R_VERSION}")
|
||||
add_definitions(-DSLIC3R_BUILD_ID=${SLIC3R_BUILD_ID})
|
||||
|
||||
set(jni_imports ${CMAKE_SOURCE_DIR}/src/main/jniImports)
|
||||
@@ -40,10 +40,10 @@ elseif (${ANDROID_ABI} STREQUAL "x86")
|
||||
set(BOOST_ARCH "x32")
|
||||
endif()
|
||||
|
||||
set(BOOST_LIBS atomic charconv chrono container context contract coroutine date_time exception fiber
|
||||
set(BOOST_LIBS atomic charconv chrono container contract date_time exception
|
||||
filesystem graph iostreams json log log_setup math_c99 math_c99f math_c99l math_tr1 math_tr1f
|
||||
math_tr1l nowide prg_exec_monitor program_options random regex serialization stacktrace_basic
|
||||
stacktrace_noop system test_exec_moinotr thread timer type_erasure unit_test_framework url wave
|
||||
stacktrace_noop system test_exec_monitor thread timer type_erasure unit_test_framework url wave
|
||||
wserialization)
|
||||
|
||||
foreach (NAME IN LISTS BOOST_LIBS)
|
||||
@@ -1320,12 +1320,9 @@ target_link_libraries(slic3r PRIVATE
|
||||
boost_charconv
|
||||
boost_chrono
|
||||
boost_container
|
||||
boost_context
|
||||
boost_contract
|
||||
boost_coroutine
|
||||
boost_date_time
|
||||
boost_exception
|
||||
boost_fiber
|
||||
boost_filesystem
|
||||
boost_graph
|
||||
boost_iostreams
|
||||
|
||||
+492
-3
@@ -1,3 +1,6 @@
|
||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||
import org.gradle.jvm.toolchain.JavaToolchainService
|
||||
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
}
|
||||
@@ -54,8 +57,8 @@ android {
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_21
|
||||
targetCompatibility JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
@@ -76,6 +79,13 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
def javaToolchainService = extensions.getByType(JavaToolchainService)
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
javaCompiler = javaToolchainService.compilerFor {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
}
|
||||
|
||||
static String getGitCommitHash(File dir) {
|
||||
try {
|
||||
return Runtime.getRuntime().exec("git rev-parse HEAD", null, dir).inputStream.readLines().get(0).substring(0, 10)
|
||||
@@ -100,4 +110,483 @@ dependencies {
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
implementation 'com.loopj.android:android-async-http:1.4.11'
|
||||
implementation 'androidx.activity:activity:1.10.1'
|
||||
}
|
||||
}
|
||||
|
||||
def loadLocalProperties() {
|
||||
def props = new Properties()
|
||||
def propsFile = rootProject.file("local.properties")
|
||||
if (propsFile.exists()) {
|
||||
propsFile.withInputStream { props.load(it) }
|
||||
}
|
||||
return props
|
||||
}
|
||||
|
||||
def toWslPath(String winPath) {
|
||||
return winPath.replaceAll('^([A-Za-z]):') { m -> "/mnt/${m[1].toLowerCase()}" }.replace('\\', '/')
|
||||
}
|
||||
|
||||
def localProps = loadLocalProperties()
|
||||
def sdkDir = localProps.getProperty("sdk.dir") ?: System.getenv("ANDROID_SDK_ROOT") ?: System.getenv("ANDROID_HOME")
|
||||
if (!sdkDir) {
|
||||
throw new GradleException("Missing sdk.dir in local.properties and ANDROID_SDK_ROOT/ANDROID_HOME is not set")
|
||||
}
|
||||
def ndkDir = "${sdkDir}/ndk/${android.ndkVersion}"
|
||||
if (!file(ndkDir).exists()) {
|
||||
throw new GradleException("NDK not found at ${ndkDir} (ndkVersion=${android.ndkVersion})")
|
||||
}
|
||||
def cmakeRoot = file("${sdkDir}/cmake")
|
||||
def cmakeDir = cmakeRoot.listFiles()?.findAll { it.isDirectory() }?.sort { a, b -> b.name <=> a.name }?.first()
|
||||
if (!cmakeDir) {
|
||||
throw new GradleException("No CMake found under ${sdkDir}/cmake")
|
||||
}
|
||||
def cmakeExe = "${cmakeDir}/bin/cmake.exe"
|
||||
def ninjaExe = "${cmakeDir}/bin/ninja.exe"
|
||||
def toolchainFile = "${ndkDir}/build/cmake/android.toolchain.cmake"
|
||||
def wslExe = "${System.getenv("SystemRoot") ?: "C:/Windows"}/System32/wsl.exe"
|
||||
|
||||
def tbbSrc = "${rootDir}/third_party/openvdb-android/tbb-aarch64"
|
||||
def tbbBuildArm64 = "${rootDir}/third_party/openvdb-android/build-tbb-android-21-arm64"
|
||||
def tbbInstallArm64 = "${rootDir}/third_party/openvdb-android/dist-android-21-arm64"
|
||||
def tbbBuildArmv7 = "${rootDir}/third_party/openvdb-android/build-tbb-android-21-armv7"
|
||||
def tbbInstallArmv7 = "${rootDir}/third_party/openvdb-android/dist-android-21-armv7"
|
||||
|
||||
def occtSrc = "${rootDir}/third_party/occt"
|
||||
def occtBuildArm64 = "${rootDir}/third_party/occt/build-android-arm64-v8a"
|
||||
def occtDistArm64 = "${rootDir}/third_party/occt/dist/android-arm64-v8a"
|
||||
def occtBuildArmv7 = "${rootDir}/third_party/occt/build-android-armeabi-v7a"
|
||||
def occtDistArmv7 = "${rootDir}/third_party/occt/dist/android-armeabi-v7a"
|
||||
|
||||
def boostDir = "${rootDir}/third_party/Boost-for-Android"
|
||||
def boostOutArm64 = "${boostDir}/build/out/arm64-v8a"
|
||||
def boostOutArmv7 = "${boostDir}/build/out/armeabi-v7a"
|
||||
|
||||
tasks.register("ensureThirdParty") {
|
||||
doLast {
|
||||
def thirdPartyDir = file("${rootDir}/third_party")
|
||||
if (!thirdPartyDir.exists()) {
|
||||
thirdPartyDir.mkdirs()
|
||||
}
|
||||
def repos = [
|
||||
[path: "${rootDir}/third_party/Boost-for-Android", url: "https://github.com/moritz-wundke/Boost-for-Android.git"],
|
||||
[path: "${rootDir}/third_party/openvdb-android", url: "https://github.com/syoyo/openvdb-android.git"],
|
||||
[path: "${rootDir}/third_party/occt", url: "https://github.com/Open-Cascade-SAS/OCCT.git"]
|
||||
]
|
||||
repos.each { repo ->
|
||||
if (!file(repo.path).exists()) {
|
||||
exec {
|
||||
workingDir rootDir
|
||||
commandLine "git", "clone", "--depth", "1", repo.url, repo.path
|
||||
}
|
||||
}
|
||||
}
|
||||
def vdbRoot = file("${rootDir}/third_party/openvdb-android")
|
||||
if (file("${vdbRoot}/.gitmodules").exists() && !file("${vdbRoot}/tbb-aarch64/CMakeLists.txt").exists()) {
|
||||
exec {
|
||||
workingDir vdbRoot
|
||||
commandLine "git", "submodule", "update", "--init", "--recursive"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("patchBoostForAndroid") {
|
||||
dependsOn("ensureThirdParty")
|
||||
doLast {
|
||||
def scriptFile = file("${boostDir}/build-android.sh")
|
||||
if (scriptFile.exists()) {
|
||||
def scriptText = scriptFile.getText("UTF-8")
|
||||
def changed = false
|
||||
|
||||
if (!scriptText.contains("FORCE_PLATFORM_OS")) {
|
||||
def marker = "# Check platform patch"
|
||||
def markerIdx = scriptText.indexOf(marker)
|
||||
if (markerIdx >= 0) {
|
||||
def esacIdx = scriptText.indexOf("esac", markerIdx)
|
||||
if (esacIdx >= 0) {
|
||||
def insertPos = scriptText.indexOf("\n", esacIdx)
|
||||
if (insertPos >= 0) {
|
||||
insertPos += 1
|
||||
def insert = 'if [ -n "${FORCE_PLATFORM_OS}" ]; then\n' +
|
||||
' PlatformOS="${FORCE_PLATFORM_OS}"\n' +
|
||||
'fi\n\n'
|
||||
scriptText = scriptText.substring(0, insertPos) + insert + scriptText.substring(insertPos)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!scriptText.contains("CXXPATH.exe")) {
|
||||
def marker = 'if [ -n "${AndroidSourcesDetected}"'
|
||||
if (scriptText.contains(marker)) {
|
||||
def insert = 'if [ ! -f "$CXXPATH" ] && [ -f "$CXXPATH.exe" ]; then\n' +
|
||||
' CXXPATH="$CXXPATH.exe"\n' +
|
||||
'fi\n\n'
|
||||
scriptText = scriptText.replace(marker, insert + marker)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
scriptFile.write(scriptText, "UTF-8")
|
||||
}
|
||||
}
|
||||
|
||||
def commonFile = file("${boostDir}/configs/user-config-ndk23-1_85_0-common.jam")
|
||||
if (commonFile.exists()) {
|
||||
def commonText = commonFile.getText("UTF-8")
|
||||
def commonChanged = false
|
||||
if (!commonText.contains("AndroidToolSuffix")) {
|
||||
def header = 'import os ;\n' +
|
||||
'local AndroidToolSuffix = [ os.environ AndroidToolSuffix ] ;\n' +
|
||||
'if ! $(AndroidToolSuffix) { AndroidToolSuffix = "" ; }\n\n'
|
||||
commonText = header + commonText.trim() + "\n"
|
||||
commonChanged = true
|
||||
}
|
||||
if (!commonText.contains('llvm-ar$(AndroidToolSuffix)')) {
|
||||
commonText = commonText.replace('<archiver>$(AndroidBinariesPath)/llvm-ar', '<archiver>$(AndroidBinariesPath)/llvm-ar$(AndroidToolSuffix)')
|
||||
commonChanged = true
|
||||
}
|
||||
if (!commonText.contains('llvm-ranlib$(AndroidToolSuffix)')) {
|
||||
commonText = commonText.replace('<ranlib>$(AndroidBinariesPath)/llvm-ranlib', '<ranlib>$(AndroidBinariesPath)/llvm-ranlib$(AndroidToolSuffix)')
|
||||
commonChanged = true
|
||||
}
|
||||
if (commonChanged) {
|
||||
commonFile.write(commonText, "UTF-8")
|
||||
}
|
||||
}
|
||||
|
||||
def arm64File = file("${boostDir}/configs/user-config-ndk23-1_85_0-arm64-v8a.jam")
|
||||
if (arm64File.exists()) {
|
||||
def text = arm64File.getText("UTF-8")
|
||||
if (!text.contains("<arch>")) {
|
||||
text = "<arch>arm\n<address-model>64\n<binary-format>elf\n<abi>aapcs\n" + text
|
||||
arm64File.write(text, "UTF-8")
|
||||
}
|
||||
}
|
||||
|
||||
def armv7File = file("${boostDir}/configs/user-config-ndk23-1_85_0-armeabi-v7a.jam")
|
||||
if (armv7File.exists()) {
|
||||
def text = armv7File.getText("UTF-8")
|
||||
if (!text.contains("<arch>")) {
|
||||
text = "<arch>arm\n<address-model>32\n<binary-format>elf\n<abi>aapcs\n" + text
|
||||
armv7File.write(text, "UTF-8")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("buildTbbArm64") {
|
||||
dependsOn("ensureThirdParty")
|
||||
onlyIf {
|
||||
!file("${projectDir}/src/main/jniImports/oneTBB/lib/arm64-v8a/libtbb.a").exists() ||
|
||||
!file("${projectDir}/src/main/jniImports/oneTBB/lib/arm64-v8a/libtbbmalloc.a").exists() ||
|
||||
!file("${projectDir}/src/main/jniLibs/arm64-v8a/libtbb.so").exists() ||
|
||||
!file("${projectDir}/src/main/jniLibs/arm64-v8a/libtbbmalloc.so").exists()
|
||||
}
|
||||
doLast {
|
||||
exec {
|
||||
commandLine cmakeExe, "-G", "Ninja",
|
||||
"-S", tbbSrc,
|
||||
"-B", tbbBuildArm64,
|
||||
"-DCMAKE_MAKE_PROGRAM=${ninjaExe}",
|
||||
"-DCMAKE_TOOLCHAIN_FILE=${toolchainFile}",
|
||||
"-DANDROID_ABI=arm64-v8a",
|
||||
"-DANDROID_PLATFORM=android-21",
|
||||
"-DANDROID_STL=c++_shared",
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DCMAKE_INSTALL_PREFIX=${tbbInstallArm64}",
|
||||
"-DTBB_BUILD_TESTS=Off"
|
||||
}
|
||||
exec {
|
||||
commandLine cmakeExe, "--build", tbbBuildArm64, "--target", "install"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("buildTbbArmv7") {
|
||||
dependsOn("ensureThirdParty")
|
||||
onlyIf {
|
||||
!file("${projectDir}/src/main/jniImports/oneTBB/lib/armeabi-v7a/libtbb.a").exists() ||
|
||||
!file("${projectDir}/src/main/jniImports/oneTBB/lib/armeabi-v7a/libtbbmalloc.a").exists() ||
|
||||
!file("${projectDir}/src/main/jniLibs/armeabi-v7a/libtbb.so").exists() ||
|
||||
!file("${projectDir}/src/main/jniLibs/armeabi-v7a/libtbbmalloc.so").exists()
|
||||
}
|
||||
doLast {
|
||||
exec {
|
||||
commandLine cmakeExe, "-G", "Ninja",
|
||||
"-S", tbbSrc,
|
||||
"-B", tbbBuildArmv7,
|
||||
"-DCMAKE_MAKE_PROGRAM=${ninjaExe}",
|
||||
"-DCMAKE_TOOLCHAIN_FILE=${toolchainFile}",
|
||||
"-DANDROID_ABI=armeabi-v7a",
|
||||
"-DANDROID_PLATFORM=android-21",
|
||||
"-DANDROID_STL=c++_shared",
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DCMAKE_INSTALL_PREFIX=${tbbInstallArmv7}",
|
||||
"-DTBB_BUILD_TESTS=Off"
|
||||
}
|
||||
exec {
|
||||
commandLine cmakeExe, "--build", tbbBuildArmv7, "--target", "install"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("copyTbbArm64", Copy) {
|
||||
dependsOn("buildTbbArm64")
|
||||
onlyIf {
|
||||
!file("${projectDir}/src/main/jniImports/oneTBB/lib/arm64-v8a/libtbb.a").exists() ||
|
||||
!file("${projectDir}/src/main/jniImports/oneTBB/lib/arm64-v8a/libtbbmalloc.a").exists() ||
|
||||
!file("${projectDir}/src/main/jniLibs/arm64-v8a/libtbb.so").exists() ||
|
||||
!file("${projectDir}/src/main/jniLibs/arm64-v8a/libtbbmalloc.so").exists()
|
||||
}
|
||||
from("${tbbInstallArm64}/lib") {
|
||||
include "libtbb_static.a"
|
||||
include "libtbbmalloc_static.a"
|
||||
include "libtbb.so"
|
||||
include "libtbbmalloc.so"
|
||||
}
|
||||
into("${projectDir}/src/main/jniImports/oneTBB/tmp-arm64")
|
||||
doLast {
|
||||
copy {
|
||||
from "${projectDir}/src/main/jniImports/oneTBB/tmp-arm64/libtbb_static.a"
|
||||
into "${projectDir}/src/main/jniImports/oneTBB/lib/arm64-v8a"
|
||||
rename { "libtbb.a" }
|
||||
}
|
||||
copy {
|
||||
from "${projectDir}/src/main/jniImports/oneTBB/tmp-arm64/libtbbmalloc_static.a"
|
||||
into "${projectDir}/src/main/jniImports/oneTBB/lib/arm64-v8a"
|
||||
rename { "libtbbmalloc.a" }
|
||||
}
|
||||
copy {
|
||||
from "${projectDir}/src/main/jniImports/oneTBB/tmp-arm64/libtbb.so"
|
||||
into "${projectDir}/src/main/jniLibs/arm64-v8a"
|
||||
}
|
||||
copy {
|
||||
from "${projectDir}/src/main/jniImports/oneTBB/tmp-arm64/libtbbmalloc.so"
|
||||
into "${projectDir}/src/main/jniLibs/arm64-v8a"
|
||||
}
|
||||
delete("${projectDir}/src/main/jniImports/oneTBB/tmp-arm64")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("copyTbbArmv7", Copy) {
|
||||
dependsOn("buildTbbArmv7")
|
||||
onlyIf {
|
||||
!file("${projectDir}/src/main/jniImports/oneTBB/lib/armeabi-v7a/libtbb.a").exists() ||
|
||||
!file("${projectDir}/src/main/jniImports/oneTBB/lib/armeabi-v7a/libtbbmalloc.a").exists() ||
|
||||
!file("${projectDir}/src/main/jniLibs/armeabi-v7a/libtbb.so").exists() ||
|
||||
!file("${projectDir}/src/main/jniLibs/armeabi-v7a/libtbbmalloc.so").exists()
|
||||
}
|
||||
from("${tbbInstallArmv7}/lib") {
|
||||
include "libtbb_static.a"
|
||||
include "libtbbmalloc_static.a"
|
||||
include "libtbb.so"
|
||||
include "libtbbmalloc.so"
|
||||
}
|
||||
into("${projectDir}/src/main/jniImports/oneTBB/tmp-armv7")
|
||||
doLast {
|
||||
copy {
|
||||
from "${projectDir}/src/main/jniImports/oneTBB/tmp-armv7/libtbb_static.a"
|
||||
into "${projectDir}/src/main/jniImports/oneTBB/lib/armeabi-v7a"
|
||||
rename { "libtbb.a" }
|
||||
}
|
||||
copy {
|
||||
from "${projectDir}/src/main/jniImports/oneTBB/tmp-armv7/libtbbmalloc_static.a"
|
||||
into "${projectDir}/src/main/jniImports/oneTBB/lib/armeabi-v7a"
|
||||
rename { "libtbbmalloc.a" }
|
||||
}
|
||||
copy {
|
||||
from "${projectDir}/src/main/jniImports/oneTBB/tmp-armv7/libtbb.so"
|
||||
into "${projectDir}/src/main/jniLibs/armeabi-v7a"
|
||||
}
|
||||
copy {
|
||||
from "${projectDir}/src/main/jniImports/oneTBB/tmp-armv7/libtbbmalloc.so"
|
||||
into "${projectDir}/src/main/jniLibs/armeabi-v7a"
|
||||
}
|
||||
delete("${projectDir}/src/main/jniImports/oneTBB/tmp-armv7")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("copyTbbHeaders") {
|
||||
dependsOn("buildTbbArm64")
|
||||
onlyIf { !file("${projectDir}/src/main/jniImports/oneTBB/include/tbb/tbb.h").exists() }
|
||||
doLast {
|
||||
copy {
|
||||
from "${tbbInstallArm64}/include/tbb"
|
||||
into "${projectDir}/src/main/jniImports/oneTBB/include/tbb"
|
||||
}
|
||||
copy {
|
||||
from "${projectDir}/src/main/jniImports/oneTBB/include/tbb"
|
||||
into "${projectDir}/src/main/jniImports/oneTBB/include/oneapi/tbb"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("buildBoostArm64") {
|
||||
dependsOn("patchBoostForAndroid")
|
||||
onlyIf { !file("${projectDir}/src/main/jniImports/boost/lib/arm64-v8a/lib/libboost_atomic-clang-mt-a64-1_85.a").exists() }
|
||||
doLast {
|
||||
if (!file(wslExe).exists()) {
|
||||
throw new GradleException("WSL is required to build Boost. Install WSL or provide prebuilt Boost libs.")
|
||||
}
|
||||
def ndkWsl = toWslPath(ndkDir)
|
||||
def boostWsl = toWslPath(boostDir)
|
||||
def binWsl = toWslPath("${ndkDir}/toolchains/llvm/prebuilt/windows-x86_64/bin")
|
||||
exec {
|
||||
commandLine wslExe, "bash", "-lc", "set -euo pipefail; cd ${boostWsl}; chmod +x ${binWsl}/aarch64-linux-android21-clang++ ${binWsl}/llvm-ar.exe ${binWsl}/llvm-ranlib.exe || true; FORCE_PLATFORM_OS=windows AndroidCompilerSuffix= AndroidToolSuffix=.exe ./build-android.sh ${ndkWsl} --boost=1.85.0 --arch=arm64-v8a --target-version=21 --without-libraries=context,coroutine,fiber,python"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("buildBoostArmv7") {
|
||||
dependsOn("patchBoostForAndroid")
|
||||
onlyIf { !file("${projectDir}/src/main/jniImports/boost/lib/armeabi-v7a/lib/libboost_atomic-clang-mt-a32-1_85.a").exists() }
|
||||
doLast {
|
||||
if (!file(wslExe).exists()) {
|
||||
throw new GradleException("WSL is required to build Boost. Install WSL or provide prebuilt Boost libs.")
|
||||
}
|
||||
def ndkWsl = toWslPath(ndkDir)
|
||||
def boostWsl = toWslPath(boostDir)
|
||||
def binWsl = toWslPath("${ndkDir}/toolchains/llvm/prebuilt/windows-x86_64/bin")
|
||||
exec {
|
||||
commandLine wslExe, "bash", "-lc", "set -euo pipefail; cd ${boostWsl}; chmod +x ${binWsl}/armv7a-linux-androideabi21-clang++ ${binWsl}/llvm-ar.exe ${binWsl}/llvm-ranlib.exe || true; FORCE_PLATFORM_OS=windows AndroidCompilerSuffix= AndroidToolSuffix=.exe ./build-android.sh ${ndkWsl} --boost=1.85.0 --arch=armeabi-v7a --target-version=21 --without-libraries=context,coroutine,fiber,python"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("copyBoostArm64", Copy) {
|
||||
dependsOn("buildBoostArm64")
|
||||
onlyIf { !file("${projectDir}/src/main/jniImports/boost/lib/arm64-v8a/lib/libboost_atomic-clang-mt-a64-1_85.a").exists() }
|
||||
from("${boostOutArm64}/lib") {
|
||||
include "libboost_*.a"
|
||||
}
|
||||
into("${projectDir}/src/main/jniImports/boost/lib/arm64-v8a/lib")
|
||||
}
|
||||
|
||||
tasks.register("copyBoostArmv7", Copy) {
|
||||
dependsOn("buildBoostArmv7")
|
||||
onlyIf { !file("${projectDir}/src/main/jniImports/boost/lib/armeabi-v7a/lib/libboost_atomic-clang-mt-a32-1_85.a").exists() }
|
||||
from("${boostOutArmv7}/lib") {
|
||||
include "libboost_*.a"
|
||||
}
|
||||
into("${projectDir}/src/main/jniImports/boost/lib/armeabi-v7a/lib")
|
||||
}
|
||||
|
||||
tasks.register("copyBoostHeaders", Copy) {
|
||||
dependsOn("ensureThirdParty")
|
||||
onlyIf { !file("${projectDir}/src/main/jniImports/boost/include/boost/variant.hpp").exists() }
|
||||
from("${boostDir}/boost_1_85_0/boost")
|
||||
into("${projectDir}/src/main/jniImports/boost/include/boost")
|
||||
}
|
||||
|
||||
tasks.register("buildOcctArm64") {
|
||||
dependsOn("ensureThirdParty")
|
||||
onlyIf { !file("${projectDir}/src/main/occt/jniLibs/arm64-v8a/libTKDESTEP.so").exists() }
|
||||
doLast {
|
||||
exec {
|
||||
commandLine cmakeExe, "-G", "Ninja",
|
||||
"-S", occtSrc,
|
||||
"-B", occtBuildArm64,
|
||||
"-DCMAKE_MAKE_PROGRAM=${ninjaExe}",
|
||||
"-DCMAKE_TOOLCHAIN_FILE=${toolchainFile}",
|
||||
"-DANDROID_ABI=arm64-v8a",
|
||||
"-DANDROID_PLATFORM=android-21",
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DBUILD_LIBRARY_TYPE=Shared",
|
||||
"-DINSTALL_DIR_LIB=libs/arm64-v8a",
|
||||
"-DINSTALL_DIR_INCLUDE=inc",
|
||||
"-DBUILD_DOC_Overview=OFF",
|
||||
"-DBUILD_DOC_RefMan=OFF",
|
||||
"-DUSE_FREETYPE=OFF",
|
||||
"-DUSE_RAPIDJSON=OFF",
|
||||
"-DUSE_DRACO=OFF",
|
||||
"-DCMAKE_INSTALL_PREFIX=${occtDistArm64}"
|
||||
}
|
||||
exec {
|
||||
commandLine cmakeExe, "--build", occtBuildArm64, "--target", "install", "--config", "Release", "--", "-j2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("buildOcctArmv7") {
|
||||
dependsOn("ensureThirdParty")
|
||||
onlyIf { !file("${projectDir}/src/main/occt/jniLibs/armeabi-v7a/libTKDESTEP.so").exists() }
|
||||
doLast {
|
||||
exec {
|
||||
commandLine cmakeExe, "-G", "Ninja",
|
||||
"-S", occtSrc,
|
||||
"-B", occtBuildArmv7,
|
||||
"-DCMAKE_MAKE_PROGRAM=${ninjaExe}",
|
||||
"-DCMAKE_TOOLCHAIN_FILE=${toolchainFile}",
|
||||
"-DANDROID_ABI=armeabi-v7a",
|
||||
"-DANDROID_PLATFORM=android-21",
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DBUILD_LIBRARY_TYPE=Shared",
|
||||
"-DINSTALL_DIR_LIB=libs/armeabi-v7a",
|
||||
"-DINSTALL_DIR_INCLUDE=inc",
|
||||
"-DBUILD_DOC_Overview=OFF",
|
||||
"-DBUILD_DOC_RefMan=OFF",
|
||||
"-DUSE_FREETYPE=OFF",
|
||||
"-DUSE_RAPIDJSON=OFF",
|
||||
"-DUSE_DRACO=OFF",
|
||||
"-DCMAKE_INSTALL_PREFIX=${occtDistArmv7}"
|
||||
}
|
||||
exec {
|
||||
commandLine cmakeExe, "--build", occtBuildArmv7, "--target", "install", "--config", "Release", "--", "-j2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("copyOcctArm64", Copy) {
|
||||
dependsOn("buildOcctArm64")
|
||||
onlyIf { !file("${projectDir}/src/main/occt/jniLibs/arm64-v8a/libTKDESTEP.so").exists() }
|
||||
from("${occtDistArm64}/libs/arm64-v8a") {
|
||||
include "*.so"
|
||||
}
|
||||
into("${projectDir}/src/main/occt/jniLibs/arm64-v8a")
|
||||
}
|
||||
|
||||
tasks.register("copyOcctArmv7", Copy) {
|
||||
dependsOn("buildOcctArmv7")
|
||||
onlyIf { !file("${projectDir}/src/main/occt/jniLibs/armeabi-v7a/libTKDESTEP.so").exists() }
|
||||
from("${occtDistArmv7}/libs/armeabi-v7a") {
|
||||
include "*.so"
|
||||
}
|
||||
into("${projectDir}/src/main/occt/jniLibs/armeabi-v7a")
|
||||
}
|
||||
|
||||
tasks.register("copyOcctHeadersArm64", Copy) {
|
||||
dependsOn("buildOcctArm64")
|
||||
onlyIf { !file("${projectDir}/src/main/occt/include/arm64-v8a/STEPCAFControl_Reader.hxx").exists() }
|
||||
from("${occtDistArm64}/inc")
|
||||
into("${projectDir}/src/main/occt/include/arm64-v8a")
|
||||
}
|
||||
|
||||
tasks.register("copyOcctHeadersArmv7", Copy) {
|
||||
dependsOn("buildOcctArmv7")
|
||||
onlyIf { !file("${projectDir}/src/main/occt/include/armeabi-v7a/STEPCAFControl_Reader.hxx").exists() }
|
||||
from("${occtDistArmv7}/inc")
|
||||
into("${projectDir}/src/main/occt/include/armeabi-v7a")
|
||||
}
|
||||
|
||||
tasks.register("prepareNativeDeps") {
|
||||
dependsOn(
|
||||
"copyTbbArm64",
|
||||
"copyTbbArmv7",
|
||||
"copyTbbHeaders",
|
||||
"copyBoostArm64",
|
||||
"copyBoostArmv7",
|
||||
"copyBoostHeaders",
|
||||
"copyOcctArm64",
|
||||
"copyOcctArmv7",
|
||||
"copyOcctHeadersArm64",
|
||||
"copyOcctHeadersArmv7"
|
||||
)
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
tasks.matching { it.name.startsWith("buildCMake") }.configureEach {
|
||||
dependsOn("prepareNativeDeps")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,13 +101,26 @@ public class SliceBeam extends Application {
|
||||
|
||||
public static ConfigObject buildCurrentConfigObject() {
|
||||
ConfigObject singleObject = new ConfigObject();
|
||||
singleObject.values.putAll(SliceBeam.CONFIG.findPrinter(SliceBeam.CONFIG.presets.get("printer")).values);
|
||||
if (SliceBeam.CONFIG.findPrint(SliceBeam.CONFIG.presets.get("print")) != null) {
|
||||
singleObject.values.putAll(SliceBeam.CONFIG.findPrint(SliceBeam.CONFIG.presets.get("print")).values);
|
||||
ConfigObject printerConfig = SliceBeam.CONFIG.findPrinter(SliceBeam.CONFIG.presets.get("printer"));
|
||||
if (printerConfig != null) {
|
||||
singleObject.values.putAll(printerConfig.values);
|
||||
}
|
||||
ConfigObject printConfig = SliceBeam.CONFIG.findPrint(SliceBeam.CONFIG.presets.get("print"));
|
||||
if (printConfig != null) {
|
||||
for (Map.Entry<String, String> en : printConfig.values.entrySet()) {
|
||||
if (!Slic3rConfigWrapper.PRINTER_CONFIG_KEYS.contains(en.getKey())) {
|
||||
singleObject.values.put(en.getKey(), en.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: MMU. Detect by printerConfig#getExtruderCount()
|
||||
if (SliceBeam.CONFIG.findFilament(SliceBeam.CONFIG.presets.get("filament")) != null) {
|
||||
singleObject.values.putAll(SliceBeam.CONFIG.findFilament(SliceBeam.CONFIG.presets.get("filament")).values);
|
||||
ConfigObject filamentConfig = SliceBeam.CONFIG.findFilament(SliceBeam.CONFIG.presets.get("filament"));
|
||||
if (filamentConfig != null) {
|
||||
for (Map.Entry<String, String> en : filamentConfig.values.entrySet()) {
|
||||
if (!Slic3rConfigWrapper.PRINTER_CONFIG_KEYS.contains(en.getKey())) {
|
||||
singleObject.values.put(en.getKey(), en.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PrintConfigDef def = PrintConfigDef.getInstance();
|
||||
@@ -121,12 +134,10 @@ public class SliceBeam extends Application {
|
||||
|
||||
public static void genCurrentConfig() throws IOException {
|
||||
File cfg = getCurrentConfigFile();
|
||||
if (!cfg.exists()) {
|
||||
FileOutputStream fos = new FileOutputStream(cfg);
|
||||
ConfigObject singleObject = buildCurrentConfigObject();
|
||||
fos.write(singleObject.serialize().getBytes(StandardCharsets.UTF_8));
|
||||
fos.close();
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(cfg);
|
||||
ConfigObject singleObject = buildCurrentConfigObject();
|
||||
fos.write(singleObject.serialize().getBytes(StandardCharsets.UTF_8));
|
||||
fos.close();
|
||||
}
|
||||
|
||||
public static File getCurrentConfigFile() {
|
||||
|
||||
@@ -51,6 +51,7 @@ import ru.ytkab0bp.slicebeam.events.SlicingProgressEvent;
|
||||
import ru.ytkab0bp.slicebeam.navigation.Fragment;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.Bed3D;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.GCodeProcessorResult;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.GCodeThumbnailer;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.Model;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.Slic3rRuntimeError;
|
||||
import ru.ytkab0bp.slicebeam.theme.ThemesRepo;
|
||||
@@ -412,12 +413,14 @@ public class BedFragment extends Fragment {
|
||||
});
|
||||
}
|
||||
|
||||
if (!DEBUG_VIEWER) {
|
||||
gCodeResult = glView.getRenderer().getModel().slice(cfg.getAbsolutePath(), gcode.getAbsolutePath(), (progress, text) -> SliceBeam.EVENT_BUS.fireEvent(new SlicingProgressEvent(progress, text)));
|
||||
SliceBeam.EVENT_BUS.fireEvent(new SlicingProgressEvent(100, ""));
|
||||
} else {
|
||||
gCodeResult = new GCodeProcessorResult(gcode);
|
||||
}
|
||||
if (!DEBUG_VIEWER) {
|
||||
gCodeResult = glView.getRenderer().getModel().slice(cfg.getAbsolutePath(), gcode.getAbsolutePath(), (progress, text) -> SliceBeam.EVENT_BUS.fireEvent(new SlicingProgressEvent(progress, text)));
|
||||
GCodeThumbnailer.addThumbnailsToGcode(gcode, SliceBeam.buildCurrentConfigObject(), glView);
|
||||
SliceBeam.EVENT_BUS.fireEvent(new SlicingProgressEvent(100, ""));
|
||||
} else {
|
||||
gCodeResult = new GCodeProcessorResult(gcode);
|
||||
GCodeThumbnailer.addThumbnailsToGcode(gcode, SliceBeam.buildCurrentConfigObject(), glView);
|
||||
}
|
||||
ViewUtils.postOnMainThread(()-> {
|
||||
glView.queueEvent(()->{
|
||||
glView.getRenderer().setGCodeViewer(gCodeResult);
|
||||
|
||||
@@ -45,8 +45,7 @@ public class PrinterConfigFragment extends ProfileListFragment {
|
||||
|
||||
new OptionElement(new SubHeader("Firmware")),
|
||||
new OptionElement(def.options.get("gcode_flavor")),
|
||||
// TODO: Thumbnails are not working *yet*
|
||||
// new OptionElement(def.options.get("thumbnails")),
|
||||
new OptionElement(def.options.get("thumbnails")),
|
||||
new OptionElement(def.options.get("silent_mode")),
|
||||
new OptionElement(def.options.get("remaining_times")),
|
||||
new OptionElement(def.options.get("binary_gcode")),
|
||||
|
||||
@@ -3,6 +3,7 @@ package ru.ytkab0bp.slicebeam.render;
|
||||
import static android.opengl.GLES30.*;
|
||||
import static ru.ytkab0bp.slicebeam.utils.DebugUtils.assertTrue;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.util.Log;
|
||||
@@ -12,6 +13,8 @@ import androidx.core.graphics.ColorUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
@@ -51,6 +54,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
||||
|
||||
// Instance values, should be released
|
||||
private Bed3D bed;
|
||||
private boolean bedVisible = true;
|
||||
private int lastConfigUid;
|
||||
private GLShadersManager shadersManager;
|
||||
private GLModel backgroundModel;
|
||||
@@ -77,6 +81,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
||||
private Vec3d bbMin = new Vec3d(), bbMax = new Vec3d();
|
||||
private boolean isInFlattenMode;
|
||||
private ArrayList<GLModel> flattenPlanes = new ArrayList<>();
|
||||
private static final double TOP_VIEW_MARGIN = 1.1;
|
||||
|
||||
public Camera getCamera() {
|
||||
return camera;
|
||||
@@ -86,6 +91,204 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
||||
return bed;
|
||||
}
|
||||
|
||||
public void setBedVisible(boolean visible) {
|
||||
bedVisible = visible;
|
||||
}
|
||||
|
||||
public boolean isBedVisible() {
|
||||
return bedVisible;
|
||||
}
|
||||
|
||||
public Bitmap renderToBitmap(int width, int height, boolean hideBed) {
|
||||
return renderToBitmap(width, height, hideBed, false);
|
||||
}
|
||||
|
||||
public Bitmap renderToBitmap(int width, int height, boolean hideBed, boolean topView) {
|
||||
if (width <= 0 || height <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int[] fbo = new int[1];
|
||||
int[] texture = new int[1];
|
||||
int[] depth = new int[1];
|
||||
int[] fboMsaa = new int[1];
|
||||
int[] colorMsaa = new int[1];
|
||||
int[] depthMsaa = new int[1];
|
||||
|
||||
glGenFramebuffers(1, fbo, 0);
|
||||
glGenTextures(1, texture, 0);
|
||||
glGenRenderbuffers(1, depth, 0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture[0]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depth[0]);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[0], 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth[0]);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDeleteRenderbuffers(1, depth, 0);
|
||||
glDeleteTextures(1, texture, 0);
|
||||
glDeleteFramebuffers(1, fbo, 0);
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean useMsaa = true;
|
||||
if (useMsaa) {
|
||||
glGenFramebuffers(1, fboMsaa, 0);
|
||||
glGenRenderbuffers(1, colorMsaa, 0);
|
||||
glGenRenderbuffers(1, depthMsaa, 0);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, colorMsaa[0]);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, width, height);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depthMsaa[0]);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fboMsaa[0]);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorMsaa[0]);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthMsaa[0]);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
useMsaa = false;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDeleteRenderbuffers(1, depthMsaa, 0);
|
||||
glDeleteRenderbuffers(1, colorMsaa, 0);
|
||||
glDeleteFramebuffers(1, fboMsaa, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int prevWidth = viewportWidth;
|
||||
int prevHeight = viewportHeight;
|
||||
boolean prevBed = bedVisible;
|
||||
CameraState prevCamera = null;
|
||||
|
||||
viewportWidth = width;
|
||||
viewportHeight = height;
|
||||
if (useMsaa) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fboMsaa[0]);
|
||||
} else {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
|
||||
}
|
||||
glViewport(0, 0, width, height);
|
||||
bedVisible = !hideBed;
|
||||
if (topView) {
|
||||
prevCamera = applyTopViewCamera();
|
||||
}
|
||||
updateProjection();
|
||||
|
||||
onDrawFrame(null);
|
||||
|
||||
if (useMsaa) {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboMsaa[0]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[0]);
|
||||
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
|
||||
}
|
||||
|
||||
Bitmap bitmap = readPixelsToBitmap(width, height);
|
||||
|
||||
if (prevCamera != null) {
|
||||
restoreCamera(prevCamera);
|
||||
}
|
||||
bedVisible = prevBed;
|
||||
viewportWidth = prevWidth;
|
||||
viewportHeight = prevHeight;
|
||||
glViewport(0, 0, prevWidth, prevHeight);
|
||||
updateProjection();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
if (useMsaa) {
|
||||
glDeleteRenderbuffers(1, depthMsaa, 0);
|
||||
glDeleteRenderbuffers(1, colorMsaa, 0);
|
||||
glDeleteFramebuffers(1, fboMsaa, 0);
|
||||
}
|
||||
glDeleteRenderbuffers(1, depth, 0);
|
||||
glDeleteTextures(1, texture, 0);
|
||||
glDeleteFramebuffers(1, fbo, 0);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private static Bitmap readPixelsToBitmap(int width, int height) {
|
||||
int[] buffer = new int[width * height];
|
||||
int[] source = new int[width * height];
|
||||
IntBuffer intBuffer = IntBuffer.wrap(buffer);
|
||||
intBuffer.position(0);
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, intBuffer);
|
||||
int offset1, offset2;
|
||||
for (int i = 0; i < height; i++) {
|
||||
offset1 = i * width;
|
||||
offset2 = (height - i - 1) * width;
|
||||
for (int j = 0; j < width; j++) {
|
||||
int texturePixel = buffer[offset1 + j];
|
||||
int blue = (texturePixel >> 16) & 0xff;
|
||||
int red = (texturePixel << 16) & 0x00ff0000;
|
||||
source[offset2 + j] = (texturePixel & 0xff00ff00) | red | blue;
|
||||
}
|
||||
}
|
||||
return Bitmap.createBitmap(source, width, height, Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
private CameraState applyTopViewCamera() {
|
||||
if (bed == null || !bed.isValid()) {
|
||||
return null;
|
||||
}
|
||||
Vec3d min;
|
||||
Vec3d max;
|
||||
if (model != null && model.getObjectsCount() > 0) {
|
||||
min = model.getBoundingBoxApproxMin();
|
||||
max = model.getBoundingBoxApproxMax();
|
||||
} else {
|
||||
min = bed.getVolumeMin();
|
||||
max = bed.getVolumeMax();
|
||||
}
|
||||
Vec3d center = min.center(max);
|
||||
double size = Math.max(max.x - min.x, max.y - min.y);
|
||||
if (size <= 0) {
|
||||
size = 1;
|
||||
}
|
||||
double fov = Math.toRadians(FOV);
|
||||
double distance = (size / 2.0) / Math.tan(fov / 2.0);
|
||||
distance *= TOP_VIEW_MARGIN;
|
||||
|
||||
CameraState state = new CameraState(camera);
|
||||
camera.origin.set(center);
|
||||
camera.position.set(center.x, center.y, max.z + distance);
|
||||
camera.up.set(0, 1, 0);
|
||||
camera.setZoom(1f);
|
||||
return state;
|
||||
}
|
||||
|
||||
private void restoreCamera(CameraState state) {
|
||||
camera.position.set(state.position);
|
||||
camera.origin.set(state.origin);
|
||||
camera.up.set(state.up);
|
||||
camera.setZoom(state.zoom);
|
||||
}
|
||||
|
||||
private static final class CameraState {
|
||||
final Vec3d position;
|
||||
final Vec3d origin;
|
||||
final Vec3d up;
|
||||
final float zoom;
|
||||
|
||||
CameraState(Camera camera) {
|
||||
position = new Vec3d(camera.position);
|
||||
origin = new Vec3d(camera.origin);
|
||||
up = new Vec3d(camera.up);
|
||||
zoom = camera.getZoom();
|
||||
}
|
||||
}
|
||||
|
||||
public double[] getProjectionMatrix() {
|
||||
return projectionMatrix;
|
||||
}
|
||||
@@ -225,7 +428,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
||||
if (lastConfigUid != SliceBeam.CONFIG_UID) {
|
||||
configureBed();
|
||||
}
|
||||
if (bed.isValid()) {
|
||||
if (bed.isValid() && bedVisible) {
|
||||
bed.render(shadersManager, bottom, camera.getViewModelMatrix(), projectionMatrix, 1f / camera.getZoom());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
package ru.ytkab0bp.slicebeam.slic3r;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.config.ConfigObject;
|
||||
import ru.ytkab0bp.slicebeam.view.GLView;
|
||||
|
||||
public final class GCodeThumbnailer {
|
||||
private static final String TAG = "GCodeThumbnailer";
|
||||
private static final int MAX_ROW_LENGTH = 78;
|
||||
private static final int THUMBNAIL_SUPERSAMPLE = 16;
|
||||
private static final int MAX_SUPERSAMPLE_PIXELS = 16_000_000;
|
||||
private static final int MAX_SUPERSAMPLE_DIM = 4096;
|
||||
private static final Pattern SIZE_PATTERN = Pattern.compile("^(\\d+)\\s*[xX]\\s*(\\d+)$");
|
||||
|
||||
private GCodeThumbnailer() {}
|
||||
|
||||
public static boolean addThumbnailsToGcode(File gcodeFile, ConfigObject config, GLView glView) {
|
||||
if (gcodeFile == null || config == null || glView == null) {
|
||||
return false;
|
||||
}
|
||||
if (!gcodeFile.exists()) {
|
||||
return false;
|
||||
}
|
||||
String binaryGcode = config.get("binary_gcode");
|
||||
if ("1".equals(binaryGcode)) {
|
||||
return false;
|
||||
}
|
||||
if (gcodeHasThumbnail(gcodeFile)) {
|
||||
return false;
|
||||
}
|
||||
String thumbnails = config.get("thumbnails");
|
||||
if (thumbnails == null || thumbnails.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
String defaultFormat = "PNG";
|
||||
|
||||
List<ThumbnailSpec> specs = parseThumbnailSpecs(thumbnails, defaultFormat);
|
||||
if (specs.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String header = buildHeader(specs, glView);
|
||||
if (header.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return prependToFile(gcodeFile, header);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to add thumbnails to gcode", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ThumbnailSpec> parseThumbnailSpecs(String thumbnails, String defaultFormat) {
|
||||
List<ThumbnailSpec> specs = new ArrayList<>();
|
||||
for (String raw : thumbnails.split(",")) {
|
||||
String token = raw.trim();
|
||||
if (token.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (token.contains("COLPIC")) {
|
||||
continue;
|
||||
}
|
||||
String format = defaultFormat;
|
||||
int slash = token.indexOf('/');
|
||||
if (slash >= 0) {
|
||||
format = token.substring(slash + 1).trim();
|
||||
token = token.substring(0, slash).trim();
|
||||
}
|
||||
Matcher matcher = SIZE_PATTERN.matcher(token);
|
||||
if (!matcher.matches()) {
|
||||
continue;
|
||||
}
|
||||
int width = Integer.parseInt(matcher.group(1));
|
||||
int height = Integer.parseInt(matcher.group(2));
|
||||
if (width <= 0 || height <= 0) {
|
||||
continue;
|
||||
}
|
||||
specs.add(new ThumbnailSpec(width, height, normalizeFormat(format)));
|
||||
}
|
||||
return specs;
|
||||
}
|
||||
|
||||
private static ThumbnailFormat normalizeFormat(String format) {
|
||||
if (format == null) {
|
||||
return ThumbnailFormat.PNG;
|
||||
}
|
||||
switch (format.trim().toUpperCase(Locale.US)) {
|
||||
case "JPG":
|
||||
case "JPEG":
|
||||
return ThumbnailFormat.JPG;
|
||||
case "QOI":
|
||||
return ThumbnailFormat.QOI;
|
||||
default:
|
||||
return ThumbnailFormat.PNG;
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap captureSnapshot(GLView glView, int targetWidth, int targetHeight) {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Bitmap[] ref = new Bitmap[1];
|
||||
int scale = computeSupersampleScale(targetWidth, targetHeight);
|
||||
int width = targetWidth * scale;
|
||||
int height = targetHeight * scale;
|
||||
glView.queueEvent(() -> {
|
||||
try {
|
||||
ref[0] = glView.snapshotBitmap(width, height, true, true);
|
||||
} catch (OutOfMemoryError e) {
|
||||
Log.e(TAG, "Thumbnail snapshot OOM", e);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to capture GL snapshot", e);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
try {
|
||||
if (!latch.await(3, TimeUnit.SECONDS)) {
|
||||
Log.w(TAG, "Timed out waiting for GL snapshot");
|
||||
return null;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return null;
|
||||
}
|
||||
Bitmap snapshot = ref[0];
|
||||
if (snapshot == null) {
|
||||
return null;
|
||||
}
|
||||
if (scale <= 1) {
|
||||
return snapshot;
|
||||
}
|
||||
Bitmap downscaled = downscaleBitmap(snapshot, targetWidth, targetHeight);
|
||||
if (downscaled != snapshot) {
|
||||
snapshot.recycle();
|
||||
}
|
||||
return downscaled;
|
||||
}
|
||||
|
||||
private static int computeSupersampleScale(int w, int h) {
|
||||
if (w <= 0 || h <= 0) {
|
||||
return 1;
|
||||
}
|
||||
int scale = THUMBNAIL_SUPERSAMPLE;
|
||||
while (scale > 1) {
|
||||
long pixels = (long) w * h * scale * scale;
|
||||
if (pixels <= MAX_SUPERSAMPLE_PIXELS && w * scale <= MAX_SUPERSAMPLE_DIM && h * scale <= MAX_SUPERSAMPLE_DIM) {
|
||||
break;
|
||||
}
|
||||
scale--;
|
||||
}
|
||||
return Math.max(1, scale);
|
||||
}
|
||||
|
||||
private static String buildHeader(List<ThumbnailSpec> specs, GLView glView) {
|
||||
StringBuilder header = new StringBuilder();
|
||||
boolean wroteThumbnail = false;
|
||||
for (ThumbnailSpec spec : specs) {
|
||||
Bitmap snapshot = captureSnapshot(glView, spec.width, spec.height);
|
||||
if (snapshot == null) {
|
||||
continue;
|
||||
}
|
||||
ThumbnailFormat format = spec.format;
|
||||
if (format == ThumbnailFormat.QOI) {
|
||||
Log.w(TAG, "QOI thumbnails not supported, falling back to PNG");
|
||||
format = ThumbnailFormat.PNG;
|
||||
}
|
||||
Bitmap scaled = snapshot;
|
||||
if (snapshot.getWidth() != spec.width || snapshot.getHeight() != spec.height) {
|
||||
scaled = downscaleBitmap(snapshot, spec.width, spec.height);
|
||||
snapshot.recycle();
|
||||
}
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
Bitmap.CompressFormat compressFormat = format == ThumbnailFormat.JPG
|
||||
? Bitmap.CompressFormat.JPEG
|
||||
: Bitmap.CompressFormat.PNG;
|
||||
int quality = format == ThumbnailFormat.JPG ? 90 : 100;
|
||||
if (!scaled.compress(compressFormat, quality, out)) {
|
||||
scaled.recycle();
|
||||
continue;
|
||||
}
|
||||
scaled.recycle();
|
||||
byte[] data = out.toByteArray();
|
||||
if (data.length == 0) {
|
||||
continue;
|
||||
}
|
||||
String tag = format == ThumbnailFormat.JPG ? "thumbnail_JPG" : "thumbnail";
|
||||
if (!wroteThumbnail) {
|
||||
header.append("; THUMBNAIL_BLOCK_START\n");
|
||||
wroteThumbnail = true;
|
||||
}
|
||||
String encoded = Base64.encodeToString(data, Base64.NO_WRAP);
|
||||
header.append("\n;\n; ").append(tag)
|
||||
.append(" begin ").append(spec.width).append("x").append(spec.height)
|
||||
.append(" ").append(encoded.length()).append("\n");
|
||||
int offset = 0;
|
||||
while (offset < encoded.length()) {
|
||||
int end = Math.min(offset + MAX_ROW_LENGTH, encoded.length());
|
||||
header.append("; ").append(encoded, offset, end).append("\n");
|
||||
offset = end;
|
||||
}
|
||||
header.append("; ").append(tag).append(" end\n;\n");
|
||||
}
|
||||
if (wroteThumbnail) {
|
||||
header.append("; THUMBNAIL_BLOCK_END\n");
|
||||
}
|
||||
return header.toString();
|
||||
}
|
||||
|
||||
private static Bitmap downscaleBitmap(Bitmap src, int targetWidth, int targetHeight) {
|
||||
if (src.getWidth() == targetWidth && src.getHeight() == targetHeight) {
|
||||
return src;
|
||||
}
|
||||
Bitmap current = src;
|
||||
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
|
||||
while (current.getWidth() / 2 >= targetWidth && current.getHeight() / 2 >= targetHeight) {
|
||||
int nextWidth = Math.max(targetWidth, current.getWidth() / 2);
|
||||
int nextHeight = Math.max(targetHeight, current.getHeight() / 2);
|
||||
Bitmap next = Bitmap.createBitmap(nextWidth, nextHeight, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(next);
|
||||
canvas.drawBitmap(current, null, new Rect(0, 0, nextWidth, nextHeight), paint);
|
||||
if (current != src) {
|
||||
current.recycle();
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
if (current.getWidth() != targetWidth || current.getHeight() != targetHeight) {
|
||||
Bitmap finalBmp = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(finalBmp);
|
||||
canvas.drawBitmap(current, null, new Rect(0, 0, targetWidth, targetHeight), paint);
|
||||
if (current != src) {
|
||||
current.recycle();
|
||||
}
|
||||
current = finalBmp;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
private static boolean prependToFile(File gcodeFile, String header) throws IOException {
|
||||
File tmp = new File(gcodeFile.getParentFile(), gcodeFile.getName() + ".thumbtmp");
|
||||
try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(gcodeFile));
|
||||
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(tmp))) {
|
||||
out.write(header.getBytes(StandardCharsets.US_ASCII));
|
||||
byte[] buffer = new byte[8192];
|
||||
int read;
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
if (!gcodeFile.delete()) {
|
||||
tmp.delete();
|
||||
return false;
|
||||
}
|
||||
if (!tmp.renameTo(gcodeFile)) {
|
||||
tmp.delete();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean gcodeHasThumbnail(File gcodeFile) {
|
||||
try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(gcodeFile))) {
|
||||
byte[] buffer = new byte[8192];
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int total = 0;
|
||||
int read;
|
||||
while ((read = in.read(buffer)) != -1 && total < 262144) {
|
||||
sb.append(new String(buffer, 0, read, StandardCharsets.US_ASCII));
|
||||
if (sb.indexOf("thumbnail begin") != -1 || sb.indexOf("thumbnail_JPG begin") != -1) {
|
||||
return true;
|
||||
}
|
||||
total += read;
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final class ThumbnailSpec {
|
||||
final int width;
|
||||
final int height;
|
||||
final ThumbnailFormat format;
|
||||
|
||||
ThumbnailSpec(int width, int height, ThumbnailFormat format) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.format = format;
|
||||
}
|
||||
}
|
||||
|
||||
private enum ThumbnailFormat {
|
||||
PNG,
|
||||
JPG,
|
||||
QOI
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,8 @@ public class PrintConfigDef {
|
||||
"tilt_up_finish_speed",
|
||||
"tilt_down_initial_speed",
|
||||
"tilt_down_finish_speed",
|
||||
"tower_speed"
|
||||
"tower_speed",
|
||||
"thumbnails_format"
|
||||
);
|
||||
|
||||
private static PrintConfigDef instance;
|
||||
|
||||
@@ -90,7 +90,7 @@ public class Slic3rConfigWrapper {
|
||||
"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_limits_usage", "thumbnails",
|
||||
"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",
|
||||
|
||||
@@ -25,6 +25,10 @@ import android.view.ViewConfiguration;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.R;
|
||||
import ru.ytkab0bp.slicebeam.SliceBeam;
|
||||
import ru.ytkab0bp.slicebeam.events.LongClickTranslationEvent;
|
||||
@@ -85,6 +89,7 @@ public class GLView extends GLSurfaceView implements IThemeView {
|
||||
xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
||||
|
||||
setEGLContextClientVersion(3);
|
||||
setEGLConfigChooser(new MultisampleConfigChooser());
|
||||
renderer = new GLRenderer(this);
|
||||
|
||||
setRenderer(renderer);
|
||||
@@ -242,6 +247,89 @@ public class GLView extends GLSurfaceView implements IThemeView {
|
||||
return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
public Bitmap snapshotBitmap(boolean hideBed) {
|
||||
if (!hideBed) {
|
||||
return snapshotBitmap();
|
||||
}
|
||||
|
||||
boolean prev = renderer.isBedVisible();
|
||||
renderer.setBedVisible(false);
|
||||
renderer.onDrawFrame(null);
|
||||
Bitmap snapshot = snapshotBitmap();
|
||||
renderer.setBedVisible(prev);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
public Bitmap snapshotBitmap(boolean hideBed, int scaleFactor) {
|
||||
if (scaleFactor <= 1) {
|
||||
return snapshotBitmap(hideBed);
|
||||
}
|
||||
int w = getWidth();
|
||||
int h = getHeight();
|
||||
if (w <= 0 || h <= 0) {
|
||||
return null;
|
||||
}
|
||||
return renderer.renderToBitmap(w * scaleFactor, h * scaleFactor, hideBed, false);
|
||||
}
|
||||
|
||||
public Bitmap snapshotBitmap(int width, int height, boolean hideBed) {
|
||||
return renderer.renderToBitmap(width, height, hideBed, false);
|
||||
}
|
||||
|
||||
public Bitmap snapshotBitmap(int width, int height, boolean hideBed, boolean topView) {
|
||||
return renderer.renderToBitmap(width, height, hideBed, topView);
|
||||
}
|
||||
|
||||
private static final class MultisampleConfigChooser implements EGLConfigChooser {
|
||||
private static final int EGL_OPENGL_ES2_BIT = 4;
|
||||
|
||||
@Override
|
||||
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
|
||||
int[] configSpec = {
|
||||
EGL10.EGL_RED_SIZE, 8,
|
||||
EGL10.EGL_GREEN_SIZE, 8,
|
||||
EGL10.EGL_BLUE_SIZE, 8,
|
||||
EGL10.EGL_ALPHA_SIZE, 8,
|
||||
EGL10.EGL_DEPTH_SIZE, 16,
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_SAMPLE_BUFFERS, 1,
|
||||
EGL10.EGL_SAMPLES, 4,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
EGLConfig config = chooseConfig(egl, display, configSpec);
|
||||
if (config != null) {
|
||||
return config;
|
||||
}
|
||||
|
||||
int[] fallbackSpec = {
|
||||
EGL10.EGL_RED_SIZE, 8,
|
||||
EGL10.EGL_GREEN_SIZE, 8,
|
||||
EGL10.EGL_BLUE_SIZE, 8,
|
||||
EGL10.EGL_ALPHA_SIZE, 8,
|
||||
EGL10.EGL_DEPTH_SIZE, 16,
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
return chooseConfig(egl, display, fallbackSpec);
|
||||
}
|
||||
|
||||
private EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, int[] configSpec) {
|
||||
int[] numConfigs = new int[1];
|
||||
if (!egl.eglChooseConfig(display, configSpec, null, 0, numConfigs)) {
|
||||
return null;
|
||||
}
|
||||
int count = numConfigs[0];
|
||||
if (count <= 0) {
|
||||
return null;
|
||||
}
|
||||
EGLConfig[] configs = new EGLConfig[count];
|
||||
if (!egl.eglChooseConfig(display, configSpec, configs, count, numConfigs)) {
|
||||
return null;
|
||||
}
|
||||
return configs[0];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
@@ -1021,7 +1021,9 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
|
||||
if (!export_to_binary_gcode)
|
||||
// Write information on the generator.
|
||||
file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str());
|
||||
file.write("; HEADER_BLOCK_START\n");
|
||||
file.write_format("; %s\n", Slic3r::header_slic3r_generated().c_str());
|
||||
file.write("; HEADER_BLOCK_END\n\n");
|
||||
|
||||
if (! export_to_binary_gcode) {
|
||||
// if exporting gcode in ascii format, generate the thumbnails here
|
||||
@@ -1563,13 +1565,13 @@ void GCodeGenerator::process_layers(
|
||||
[&output_stream](std::string s) { output_stream.write(s); }
|
||||
);
|
||||
|
||||
tbb::filter<void, LayerResult> pipeline_to_layerresult = smooth_path_interpolator & generator;
|
||||
auto pipeline_to_layerresult = smooth_path_interpolator & generator;
|
||||
if (m_spiral_vase)
|
||||
pipeline_to_layerresult = pipeline_to_layerresult & spiral_vase;
|
||||
if (m_pressure_equalizer)
|
||||
pipeline_to_layerresult = pipeline_to_layerresult & pressure_equalizer;
|
||||
|
||||
tbb::filter<LayerResult, std::string> pipeline_to_string = cooling;
|
||||
auto pipeline_to_string = cooling;
|
||||
if (m_find_replace)
|
||||
pipeline_to_string = pipeline_to_string & find_replace;
|
||||
|
||||
@@ -1656,13 +1658,13 @@ void GCodeGenerator::process_layers(
|
||||
[&output_stream](std::string s) { output_stream.write(s); }
|
||||
);
|
||||
|
||||
tbb::filter<void, LayerResult> pipeline_to_layerresult = smooth_path_interpolator & generator;
|
||||
auto pipeline_to_layerresult = smooth_path_interpolator & generator;
|
||||
if (m_spiral_vase)
|
||||
pipeline_to_layerresult = pipeline_to_layerresult & spiral_vase;
|
||||
if (m_pressure_equalizer)
|
||||
pipeline_to_layerresult = pipeline_to_layerresult & pressure_equalizer;
|
||||
|
||||
tbb::filter<LayerResult, std::string> pipeline_to_string = cooling;
|
||||
auto pipeline_to_string = cooling;
|
||||
if (m_find_replace)
|
||||
pipeline_to_string = pipeline_to_string & find_replace;
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
#include "BRepBuilderAPI_Transform.hxx"
|
||||
#include "TopExp_Explorer.hxx"
|
||||
#include "BRep_Tool.hxx"
|
||||
#include "NCollection_Sequence.hxx"
|
||||
|
||||
using TDF_LabelSequence = NCollection_Sequence<TDF_Label>;
|
||||
|
||||
const double STEP_TRANS_CHORD_ERROR = 0.005;
|
||||
const double STEP_TRANS_ANGLE_RES = 1;
|
||||
@@ -198,4 +201,4 @@ try {
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
}; // namespace Slic3r
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <android/log.h>
|
||||
|
||||
#include <jni.h>
|
||||
#include <thread>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.5.2'
|
||||
classpath 'com.android.tools.build:gradle:8.13.2'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Mon Aug 05 19:06:18 MSK 2024
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+41
-1
@@ -1,7 +1,47 @@
|
||||
def localPropsFile = file("local.properties")
|
||||
if (!localPropsFile.exists()) {
|
||||
def sdkRoot = System.getenv("ANDROID_SDK_ROOT") ?: System.getenv("ANDROID_HOME")
|
||||
if (!sdkRoot) {
|
||||
def localAppData = System.getenv("LOCALAPPDATA")
|
||||
if (localAppData) {
|
||||
def defaultSdk = new File(localAppData, "Android\\Sdk")
|
||||
if (defaultSdk.exists()) {
|
||||
sdkRoot = defaultSdk.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sdkRoot) {
|
||||
localPropsFile.text = "sdk.dir=${sdkRoot.replace('\\', '\\\\')}\n"
|
||||
}
|
||||
}
|
||||
|
||||
def hasSubmodules = file(".gitmodules").exists()
|
||||
def submoduleRoots = [
|
||||
file("EventBus/eventbus"),
|
||||
file("EventBus/eventbus_api"),
|
||||
file("EventBus/eventbus_processor"),
|
||||
file("SAPIL/sapil")
|
||||
]
|
||||
def missingSubmodule = submoduleRoots.any { !it.exists() }
|
||||
if (hasSubmodules && missingSubmodule) {
|
||||
try {
|
||||
def proc = new ProcessBuilder("git", "submodule", "update", "--init", "--recursive")
|
||||
.directory(rootDir)
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
proc.inputStream.eachLine { println(it) }
|
||||
if (proc.waitFor() != 0) {
|
||||
println("Warning: git submodule update failed; run it manually if build fails.")
|
||||
}
|
||||
} catch (Exception e) {
|
||||
println("Warning: unable to run git submodule update; run it manually if build fails.")
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "Slice Beam"
|
||||
include ':app', ':eventbus', ':eventbus_api', ':eventbus_processor', ':sapil'
|
||||
|
||||
project(':eventbus').projectDir = file('EventBus/eventbus')
|
||||
project(':eventbus_api').projectDir = file('EventBus/eventbus_api')
|
||||
project(':eventbus_processor').projectDir = file('EventBus/eventbus_processor')
|
||||
project(':sapil').projectDir = file('SAPIL/sapil')
|
||||
project(':sapil').projectDir = file('SAPIL/sapil')
|
||||
Reference in New Issue
Block a user