diff --git a/.github/workflows/build_ci.yml b/.github/workflows/build_ci.yml index 9ab2a4d3..c734447b 100644 --- a/.github/workflows/build_ci.yml +++ b/.github/workflows/build_ci.yml @@ -28,7 +28,7 @@ jobs: with: name: eocvsim-ubuntu-latest path: | - EOCV-Sim/build/libs/*.jar + VisionBench/build/libs/*.jar build_linux_arm: runs-on: ubuntu-24.04-arm @@ -51,7 +51,7 @@ jobs: with: name: eocvsim-ubuntu-arm64 path: | - EOCV-Sim/build/libs/*.jar + VisionBench/build/libs/*.jar build_windows: runs-on: windows-latest @@ -73,7 +73,7 @@ jobs: with: name: eocvsim-windows-latest path: | - EOCV-Sim/build/libs/*.jar + VisionBench/build/libs/*.jar build_mac: runs-on: macos-26 @@ -96,7 +96,7 @@ jobs: with: name: eocvsim-macos-latest path: | - EOCV-Sim/build/libs/*.jar + VisionBench/build/libs/*.jar build_mac_intel: runs-on: macos-26-intel @@ -119,7 +119,7 @@ jobs: with: name: eocvsim-macos-13 path: | - EOCV-Sim/build/libs/*.jar + VisionBench/build/libs/*.jar release: needs: [build_linux, build_linux_arm, build_windows, build_mac, build_mac_intel] @@ -143,7 +143,7 @@ jobs: ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.JRELEASER_MAVENCENTRAL_PASSWORD }} ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.JRELEASER_GPG_PASSPHRASE }} ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.JRELEASER_GPG_SECRET_KEY }} - run: ./gradlew -Penv=release :Common:publishToMavenCentral :Vision:publishToMavenCentral :EOCV-Sim:publishToMavenCentral -x test -x :EOCV-Sim:shadowJar + run: ./gradlew -Penv=release :Common:publishToMavenCentral :Vision:publishToMavenCentral :VisionBench:publishToMavenCentral -x test -x :VisionBench:shadowJar - name: Download Linux artifacts uses: actions/download-artifact@v4 @@ -188,15 +188,15 @@ jobs: run: | mkdir -p release-jars # Copy the first (and should be only) jar from each platform folder - cp artifacts/ubuntu/EOCV-Sim-*.jar release-jars/ 2>/dev/null || echo "No Linux jar found" - cp artifacts/ubuntu-arm64/EOCV-Sim-*.jar release-jars/ 2>/dev/null || echo "No Linux ARM64 jar found" - cp artifacts/windows/EOCV-Sim-*.jar release-jars/ 2>/dev/null || echo "No Windows jar found" - cp artifacts/macos/EOCV-Sim-*.jar release-jars/ 2>/dev/null || echo "No macOS jar found" - cp artifacts/macos-intel/EOCV-Sim-*.jar release-jars/ 2>/dev/null || echo "No Intel macOS jar found" + cp artifacts/ubuntu/VisionBench-*.jar release-jars/ 2>/dev/null || echo "No Linux jar found" jar found" + cp artifacts/ubuntu-arm64/VisionBench-*.jar release-jars/ 2>/dev/null || echo "No Linux ARM64 jar found" + cp artifacts/windows/VisionBench-*.jar release-jars/ 2>/dev/null || echo "No Windows jar found" + cp artifacts/macos/VisionBench-*.jar release-jars/ 2>/dev/null || echo "No macOS jar found" + cp artifacts/macos-intel/VisionBench-*.jar release-jars/ 2>/dev/null || echo "No Intel macOS jar found" # Remove source jars if any were copied rm -f release-jars/*-sources.jar # Remove the generic jar (no platform suffix) - find release-jars -name "EOCV-Sim-*.jar" ! -name "*x86*" ! -name "*arm*" ! -name "*win*" -delete + find release-jars -name "VisionBench-*.jar" ! -name "*x86*" ! -name "*arm*" ! -name "*win*" -delete echo "Release jars to upload:" ls -la release-jars/ @@ -247,11 +247,11 @@ jobs: run: | mkdir -p release-jars # Copy the first (and should be only) jar from each platform folder - cp artifacts/dev/ubuntu/EOCV-Sim-*.jar release-jars/ 2>/dev/null || echo "No Linux jar found" - cp artifacts/dev/ubuntu-arm64/EOCV-Sim-*.jar release-jars/ 2>/dev/null || echo "No Linux ARM64 jar found" - cp artifacts/dev/windows/EOCV-Sim-*.jar release-jars/ 2>/dev/null || echo "No Windows jar found" - cp artifacts/dev/macos/EOCV-Sim-*.jar release-jars/ 2>/dev/null || echo "No macOS jar found" - cp artifacts/dev/macos-intel/EOCV-Sim-*.jar release-jars/ 2>/dev/null || echo "No Intel macOS jar found" + cp artifacts/dev/ubuntu/VisionBench-*.jar release-jars/ 2>/dev/null || echo "No Linux jar found" + cp artifacts/dev/ubuntu-arm64/VisionBench-*.jar release-jars/ 2>/dev/null || echo "No Linux ARM64 jar found" + cp artifacts/dev/windows/VisionBench-*.jar release-jars/ 2>/dev/null || echo "No Windows jar found" + cp artifacts/dev/macos/VisionBench-*.jar release-jars/ 2>/dev/null || echo "No macOS jar found" + cp artifacts/dev/macos-intel/VisionBench-*.jar release-jars/ 2>/dev/null || echo "No Intel macOS jar found" # Remove source jars if any were copied rm -f release-jars/*-sources.jar # Remove the generic jar (no platform suffix) @@ -263,7 +263,7 @@ jobs: uses: pyTooling/Actions/releaser@r0 with: token: ${{ secrets.GITHUB_TOKEN }} - tag: 'Dev' + tag: ${{ github.ref_name }} rm: true files: | release-jars/*.jar diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..b0dafa0b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,27 @@ +# AGENTS + +This repository is the EOCV-Sim desktop simulator for OpenCV/FIRST Tech Challenge-style pipelines. + +Quick orientation: + +- `VisionBench/` contains the main app runtime, workspace tooling, configuration, GUI, plugins, and pipeline orchestration. +- `Common/` contains shared lifecycle/orchestration utilities, event handling, and cross-cutting runtime helpers. +- `Vision/` contains the rendering, camera compatibility, and FTC/OpenCV compatibility layer used to display and process frames. +- `TeamCode/` contains sample FTC-style pipelines and example code. + +For deeper architecture and subsystem details, start from the documentation index: + +- `documents/README.md` — index of architecture docs and reading order +- `documents/01-overview-and-architecture.md` — repository structure and lifecycle overview +- `documents/02-main-eocvsim.md` — main app bootstrap and runtime shell +- `documents/03-config-and-settings.md` — configuration and settings flow +- `documents/04-gui-and-visualizer.md` — GUI and viewport host +- `documents/05-pipeline-runtime.md` — pipeline execution, timeouts, and failure handling +- `documents/06-input-sources.md` — input source acquisition and runtime sources +- `documents/07-workspaces.md` — workspace compile/reload flow +- `documents/08-plugins-and-superaccess.md` — plugin/security architecture +- `documents/09-vision-and-common-libraries.md` — rendering and shared foundation layers +- `documents/10-runtime-utilities.md` — EventHandler, orchestration, and common runtime utilities +- `documents/11-tunable-fields.md` — live pipeline tuning and reflected field editing + +In short: the app is organized around a lifecycle-driven runtime, a pipeline execution engine, a desktop viewport/rendering layer, and a plugin/workspace ecosystem. The docs in `documents/` are the preferred place to understand the architecture before changing code. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..fd25442b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/Common/build.gradle b/Common/build.gradle index c2486375..1cdffe9e 100644 --- a/Common/build.gradle +++ b/Common/build.gradle @@ -3,7 +3,7 @@ plugins { id 'signing' id 'com.gradleup.shadow' id 'org.photonvision.tools.WpilibTools' - id "com.vanniktech.maven.publish" version "0.30.0" + id "com.vanniktech.maven.publish" } apply from: '../build.common.gradle' diff --git a/Common/src/main/java/org/deltacv/common/util/serialization/Toml.java b/Common/src/main/java/org/deltacv/common/util/serialization/Toml.java index 4c78a4cc..0deb2e95 100644 --- a/Common/src/main/java/org/deltacv/common/util/serialization/Toml.java +++ b/Common/src/main/java/org/deltacv/common/util/serialization/Toml.java @@ -41,7 +41,8 @@ public Toml read(File f) { public Toml read(InputStream in) { try { - Map m = MAPPER.readValue(in, new TypeReference>() {}); + Map m = MAPPER.readValue(in, new TypeReference<>() { + }); return new Toml(m); } catch (Exception e) { throw new RuntimeException("Failed to read TOML from stream", e); diff --git a/Common/src/main/java/org/deltacv/eocvsim/plugin/security/Authority.kt b/Common/src/main/java/org/deltacv/eocvsim/plugin/security/Authority.kt index 4dedf074..6287a2df 100644 --- a/Common/src/main/java/org/deltacv/eocvsim/plugin/security/Authority.kt +++ b/Common/src/main/java/org/deltacv/eocvsim/plugin/security/Authority.kt @@ -50,21 +50,25 @@ object AuthorityFetcher { private val cache = mutableMapOf() fun fetchAuthority(name: String): Authority? { - validateCache() + try { + validateCache() - // Check if the authority is cached and the file is valid - cache[name]?.let { cachedAuthority -> - logger.info("Returning cached authority for $name") - return cachedAuthority.authority + // Check if the authority is cached and the file is valid + cache[name]?.let { cachedAuthority -> + logger.info("Returning cached authority for $name") + return cachedAuthority.authority + } + } catch (e: Exception) { + logger.error("Failed to validate cache", e) } // Load authorities from file if it exists if (AUTHORITIES_FILE.exists() && tryLockAuthoritiesFile()) { try { - val authoritiesToml = Toml().read(AUTHORITIES_FILE) + val authoritiesToml = readAuthoritiesFile() ?: return null val timestamp = authoritiesToml.getLong("timestamp") - if(System.currentTimeMillis() - timestamp > TTL_DURATION_MS) { + if (System.currentTimeMillis() - (timestamp ?: 0L) > TTL_DURATION_MS) { AUTHORITIES_FILE.delete() } else { val authorityData = authoritiesToml.getTable(name) @@ -118,22 +122,43 @@ object AuthorityFetcher { return } - val currentTime = System.currentTimeMillis() + try { + val currentTime = System.currentTimeMillis() - if(!AUTHORITIES_FILE.exists()) { - AUTHORITIES_FILE.writeText("timestamp = $currentTime\n") - } + if(!AUTHORITIES_FILE.exists()) { + AUTHORITIES_FILE.writeText("timestamp = $currentTime\n") + return + } - val authoritiesToml = Toml().read(AUTHORITIES_FILE) - val timestamp = authoritiesToml.getLong("timestamp") + val authoritiesToml = readAuthoritiesFile() + val timestamp = authoritiesToml?.getLong("timestamp") - if(timestamp != null && currentTime - timestamp > TTL_DURATION_MS) { + if(timestamp != null && currentTime - timestamp > TTL_DURATION_MS) { + AUTHORITIES_FILE.delete() + logger.info("Authorities file has expired, clearing cache") + cache.clear() + } + } catch (e: Exception) { + logger.error("Authorities cache is corrupted, clearing it", e) AUTHORITIES_FILE.delete() - logger.info("Authorities file has expired, clearing cache") cache.clear() + } finally { + AUTHORITIES_LOCK_FILE.unlock() + } + } + + private fun readAuthoritiesFile(): Toml? { + if (!AUTHORITIES_FILE.exists()) { + return null } - AUTHORITIES_LOCK_FILE.unlock() + return try { + Toml().read(AUTHORITIES_FILE) + } catch (e: Exception) { + logger.warn("Authorities cache is invalid, deleting it and recreating later", e) + AUTHORITIES_FILE.delete() + null + } } private fun saveAuthorityToFile(name: String, publicKey: String) { @@ -142,23 +167,35 @@ object AuthorityFetcher { } try { - val sb = StringBuilder() + val currentTime = System.currentTimeMillis() + val existingAuthorities = linkedMapOf() - // Load existing authorities if the file exists if (AUTHORITIES_FILE.exists()) { - val existingToml = AUTHORITIES_FILE.readText() - sb.append(existingToml) - } else { - sb.append("timestamp = ${System.currentTimeMillis()}\n") + val existingToml = readAuthoritiesFile() ?: Toml() + val existingMap = existingToml.toMap().filterKeys { it != "timestamp" } + existingMap.forEach { (key, value) -> + if (value is Map<*, *>) { + existingAuthorities[key] = linkedMapOf().apply { + value.forEach { (nestedKey, nestedValue) -> put(nestedKey.toString(), nestedValue) } + } + } else { + existingAuthorities[key] = value + } + } + + val topLevelTimestamp = existingToml.getLong("timestamp") + if (topLevelTimestamp != null) { + existingAuthorities["timestamp"] = topLevelTimestamp + } } - // Append new authority information - sb.appendLine("[$name]") - sb.appendLine("public = \"$publicKey\"") - sb.appendLine("timestamp = ${System.currentTimeMillis()}") + existingAuthorities["timestamp"] = existingAuthorities["timestamp"] as? Number ?: currentTime + val authorityTable = linkedMapOf() + authorityTable["public"] = publicKey + authorityTable["timestamp"] = currentTime + existingAuthorities[name] = authorityTable - // Write the updated content to the file - AUTHORITIES_FILE.writeText(sb.toString()) + AUTHORITIES_FILE.writeText(buildAuthoritiesToml(existingAuthorities)) } catch (e: Exception) { logger.error("Failed to save authority to file", e) } finally { @@ -166,6 +203,33 @@ object AuthorityFetcher { } } + private fun buildAuthoritiesToml(authorities: Map): String { + val sb = StringBuilder() + val topLevelTimestamp = authorities["timestamp"] + if (topLevelTimestamp != null) { + sb.appendLine("timestamp = $topLevelTimestamp") + } + + for ((name, value) in authorities.filterKeys { it != "timestamp" }) { + if (value !is Map<*, *>) continue + + sb.appendLine() + sb.appendLine("[$name]") + for ((key, entryValue) in value) { + val fieldName = key.toString() + when (entryValue) { + is Number -> sb.appendLine("$fieldName = $entryValue") + is Boolean -> sb.appendLine("$fieldName = ${entryValue.toString().lowercase(Locale.ROOT)}") + is String -> sb.appendLine("$fieldName = \"$entryValue\"") + null -> sb.appendLine("$fieldName = \"\"") + else -> sb.appendLine("$fieldName = \"$entryValue\"") + } + } + } + + return sb.toString().trimEnd() + "\n" + } + private fun tryLockAuthoritiesFile(): Boolean { val time = System.currentTimeMillis() diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/ClasspathScan.kt b/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/ClasspathScan.kt deleted file mode 100644 index 4c6b742b..00000000 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/ClasspathScan.kt +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2021 Sebastian Erives - * Licensed under the MIT License. - */ - -package com.github.serivesmejia.eocvsim.util - -import com.github.serivesmejia.eocvsim.util.orchestration.Orchestrable -import com.github.serivesmejia.eocvsim.util.orchestration.Orchestrator -import com.qualcomm.robotcore.eventloop.opmode.Disabled -import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode -import com.qualcomm.robotcore.eventloop.opmode.OpMode -import com.qualcomm.robotcore.util.ElapsedTime -import io.github.classgraph.ClassGraph -import org.deltacv.common.util.loggerForThis -import org.firstinspires.ftc.vision.VisionProcessor -import org.openftc.easyopencv.OpenCvPipeline - -class InitClasspathScan : ClasspathScan(), Orchestrable { - override fun wire(orchestrator: Orchestrator) { - orchestrator.register(this) { - phase(Orchestrator.Phase.INIT) { - target { scan() } - } - } - } -} - -/** - * Classpath scanner using ClassGraph. - * - * It scans for OpenCvPipelines, OpModes, VisionProcessors and TunableFields - */ -open class ClasspathScan { - - companion object { - val ignoredPackages = arrayOf( - "java", - "kotlin", - "org.opencv", - "imgui", - "io.github.classgraph", - "org.deltacv", - "com.github.serivesmejia.eocvsim.pipeline", - "org.firstinspires.ftc.vision", - "org.lwjgl", - "org.apache", - "org.codehaus", - "com.google" - ) - } - - val logger by loggerForThis() - - var scanResult: ScanResult? = null - private set - - var hasScanned = false - private set - - /** - * Perform the classpath scan using ClassGraph, surprisingly fast due to - * the miracles of said library using bytecode scanning instead of reflection. - * - * This method will scan for OpenCvPipelines, OpModes, VisionProcessors and TunableFields - * @param jarFile the jar file to scan, if null, the classpath will be scanned - * @param classLoader the classloader to use, if null, the system classloader will be used - * @param addProcessorsAsPipelines if true, VisionProcessors will be wrapped as pipelines - */ - @Suppress("UNCHECKED_CAST") - fun scan( - jarFile: String? = null, - classLoader: ClassLoader? = null, - addProcessorsAsPipelines: Boolean = true - ): ScanResult { - val timer = ElapsedTime() - val classGraph = ClassGraph() - .enableClassInfo() - // .verbose() - .enableAnnotationInfo() - .rejectPackages(*ignoredPackages) - - if (jarFile != null) { - classGraph.overrideClasspath("$jarFile!/") - logger.info("Starting to scan for classes in $jarFile...") - } else { - logger.info("Starting to scan classpath...") - } - - if (classLoader != null) { - classGraph.overrideClassLoaders(classLoader) - } - - val scanResult = classGraph.scan() - - logger.info("ClassGraph finished scanning (took ${timer.seconds()}s)") - - - val pipelineClasses = mutableListOf>() - - // i...don't even know how to name this, sorry, future readers - // but classgraph for some reason does not have a recursive search for subclasses... - fun searchPipelinesOfSuperclass(superclass: String) { - logger.trace("searchPipelinesOfSuperclass: {}", superclass) - - val superclassClazz = if (classLoader != null) { - classLoader.loadClass(superclass) - } else Class.forName(superclass) - - val pipelineClassesInfo = if (superclassClazz.isInterface) - scanResult.getClassesImplementing(superclass) - else scanResult.getSubclasses(superclass) - - for (pipelineClassInfo in pipelineClassesInfo) { - logger.trace("pipelineClassInfo: {}", pipelineClassInfo.name) - - for (pipelineSubclassInfo in pipelineClassInfo.subclasses) { - searchPipelinesOfSuperclass(pipelineSubclassInfo.name) // naming is my passion - } - - if (pipelineClassInfo.isAbstract || pipelineClassInfo.isInterface) { - continue // nope'd outta here - } - - val clazz = if (classLoader != null) { - classLoader.loadClass(pipelineClassInfo.name) - } else Class.forName(pipelineClassInfo.name) - - logger.trace("class {} super {}", clazz.typeName, clazz.superclass.typeName) - - if (!pipelineClasses.contains(clazz) && ReflectUtil.hasSuperclass(clazz, superclassClazz)) { - if (clazz.isAnnotationPresent(Disabled::class.java)) { - logger.info("Found @Disabled pipeline ${clazz.typeName}") - } else { - logger.info("Found pipeline ${clazz.typeName}") - pipelineClasses.add(clazz) - } - } - } - } - - // start recursive hell - searchPipelinesOfSuperclass(OpenCvPipeline::class.java.name) - - if (jarFile != null) { - // Since we removed EOCV-Sim from the scan classpath, - // ClassGraph does not know that OpMode and LinearOpMode - // are subclasses of OpenCvPipeline, so we have to scan them - // manually... - searchPipelinesOfSuperclass(OpMode::class.java.name) - searchPipelinesOfSuperclass(LinearOpMode::class.java.name) - } - - if (addProcessorsAsPipelines) { - logger.info("Searching for VisionProcessors...") - searchPipelinesOfSuperclass(VisionProcessor::class.java.name) - } - - logger.info("Found ${pipelineClasses.size} pipelines") - - logger.info("Finished scanning (took ${timer.seconds()}s)") - - this.scanResult = ScanResult( - pipelineClasses - ) - - return this.scanResult!! - } - -} - -/** - * Result of the classpath scan - * @param pipelineClasses the found OpenCvPipelines - */ -data class ScanResult( - val pipelineClasses: List> -) diff --git a/EOCV-Sim/src/main/resources/opensourcelibs.txt b/EOCV-Sim/src/main/resources/opensourcelibs.txt deleted file mode 100644 index bc932b6d..00000000 --- a/EOCV-Sim/src/main/resources/opensourcelibs.txt +++ /dev/null @@ -1,13 +0,0 @@ -EOCV-Sim and its source code is distributed under the MIT License - -OpenCV - Under Apache 2.0 License -WPILib - Under BSD 3-Clause License -FTC SDK - Some source code under BSD License -EasyOpenCV - Some source code under MIT License -EOCV-AprilTag-Plugin - API under the MIT License -Skiko - Under Apache 2.0 License -Gson - Under Apache 2.0 License -ClassGraph - Under MIT License -FlatLaf - Under Apache 2.0 License -Kotlin stdlib & coroutines - Under Apache 2.0 License -picocli - Under Apache 2.0 License \ No newline at end of file diff --git a/EOCV-Sim/src/test/kotlin/com/github/serivesmejia/eocvsim/test/CoreTests.kt b/EOCV-Sim/src/test/kotlin/com/github/serivesmejia/eocvsim/test/CoreTests.kt deleted file mode 100644 index 772b1c37..00000000 --- a/EOCV-Sim/src/test/kotlin/com/github/serivesmejia/eocvsim/test/CoreTests.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2021 Sebastian Erives - * Licensed under the MIT License. - */ - -@file:Suppress("UNUSED") - -package com.github.serivesmejia.eocvsim.test - -import com.github.serivesmejia.eocvsim.util.LibraryLoader -import io.kotest.core.spec.style.StringSpec -import org.opencv.core.Mat -import org.wpilib.vision.apriltag.jni.AprilTagJNI - -class LibrariesTest : StringSpec({ - "Loading Libraries" { - LibraryLoader.loadLibraries() - } - - "Creating a Mat" { - Mat() - } - - "Create AprilTag Detector" { - val handle = AprilTagJNI.createDetector() - assert(handle != 0.toLong()) - } -}) \ No newline at end of file diff --git a/PaperVisionShadow/build.gradle b/PaperVisionShadow/build.gradle deleted file mode 100644 index 9735b5cf..00000000 --- a/PaperVisionShadow/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -plugins { - id 'kotlin' - id 'com.gradleup.shadow' -} - -apply from: '../build.common.gradle' - -shadowJar { - dependencies { - exclude "nu/pattern/*" - } - - exclude "META-INF/*.SF" - exclude "META-INF/*.DSA" - exclude "META-INF/*.RSA" - exclude "android/" - exclude "androidx/" - exclude "dalvik/" - exclude "libcore/" -} - -dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib' - - implementation("org.deltacv.PaperVision:EOCVSimPlugin:$papervision_version") -} \ No newline at end of file diff --git a/README.md b/README.md index 8ba27e90..0c5e8812 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,26 @@ - + -![Java CI with Gradle](https://github.com/deltacv/EOCV-Sim/workflows/Build%20and%20test%20with%20Gradle/badge.svg) -[![Maven Publish & Create GitHub Release(s)](https://github.com/deltacv/EOCV-Sim/actions/workflows/release_ci.yml/badge.svg)](https://github.com/deltacv/EOCV-Sim/actions/workflows/release_ci.yml) +[![Build, Test & Release](https://github.com/deltacv/EOCV-Sim/actions/workflows/build_ci.yml/badge.svg)](https://github.com/deltacv/EOCV-Sim/actions/workflows/release_ci.yml) # Welcome! -EOCV-Sim (EasyOpenCV Simulator) is a straightforward way to test your pipelines in a +VisionBench (formerly EOCV-Sim) is a straightforward way to test your pipelines in a simple user interface directly in your computer, simulating the EasyOpenCV library & a bit of FTC SDK structure, allowing you to simply copy paste directly your pipeline code once you want to transfer it onto your robot! -## Introducing PaperVision +## Introducing VisionGraph -EOCV-Sim comes with a tool that will make it even easier to work on your computer vision pipelines. -PaperVision takes inspiration in Blender and Unreal Engine's blueprint system, allowing you to create pipelines by connecting nodes together.

-PaperVision is still in its early stages, but it's already a powerful tool that will make it easier to work on your pipelines.

-Find it in the "PaperVision" tab in the simulator ! +VisionBench comes with a tool that will make it even easier to work on your computer vision pipelines. +VisionGraph takes inspiration in industry-leading node editor tools, allowing you to create pipelines by connecting nodes together.

+VisionGraph is still in its early stages, but it's already a powerful tool that will make it easier to work on your pipelines.

+Find it in the "VisionGraph" tab in the bench ! - + -# Learn how to install and use the simulator in the [documentation here](https://docs.deltacv.org/eocv-sim) -### (Common users won't need to scroll down any further from here - the docs have everything you need) +# Learn how to install and use VisionBench in the [documentation here](https://docs.deltacv.org/visionbench) # [Buy me a coffee](https://buymeacoffee.com/serivesmejia) @@ -30,6 +28,8 @@ For the past 4 years I've been developing and maintaining learning tools for rob \- Sebastian Erives, deltacv's main dev +### (Common users won't need to scroll down any further from here - the docs have everything you need) + # Acknowledgments YourKit supports open source projects with innovative and intelligent tools @@ -62,33 +62,23 @@ Follow the steps in [this page](https://docs.deltacv.org/eocv-sim/downloading-eo ### Gradle ```groovy repositories { - maven { url 'https://jitpack.com' } //add jitpack as a maven repo mavenCentral() //add maven central as a maven repo } dependencies { - implementation 'com.github.deltacv:EOCV-Sim:3.3.2' // add the EOCV-Sim dependency, make sure to replace for the latest version + implementation 'org.deltacv.VisionBench:VisionBench:2027.0.0' // add the VisionBench dependency, make sure to replace for the latest version } ``` ## Maven - Adding the jitpack maven repo - ```xml - - - jitpack.io - https://jitpack.io - - - ``` - Adding the EOCV-Sim dependecy + Adding the VisionBench dependency ```xml - com.github.deltacv - EOCV-Sim - 3.3.2 + org.deltacv.VisionBench + VisionBench + 2027.0.0 ``` @@ -99,7 +89,41 @@ Join the [deltacv discord server](https://discord.gg/A3RMYzf6DA) ! # Change logs -### Formerly, EOCV-Sim was hosted on a [personal account repo](https://github.com/serivesmejia/EOCV-Sim/). Released prior to 3.0.0 can be found there for historic purposes. +### Formerly, VisionBench was hosted on a [personal account repo](https://github.com/serivesmejia/EOCV-Sim/). Released prior to 3.0.0 can be found there for historic purposes. + +## [v2027.0.0 - Welcome to VisionBench](https://github.com/deltacv/EOCV-Sim/releases/tag/v2027.0.0) + +* This is the 38th release for VisionBench (formerly EOCV-Sim) + + * Major milestone release featuring the official project rebrand to **VisionBench**, the renaming of PaperVision to **VisionGraph**, and the transition to Season-based Calendar Versioning (CalVer) aligned with WPILib 2027 + * **Semantic Versioning Transition (CalVer)**: + * **BREAKING**: VisionBench has transitioned from sequential Semantic Versioning (`v4.x.x`) to **Season-based Calendar Versioning** (`vYYYY.Minor.Patch`), kicking off with `v2027.0.0`. + * **Why the change**: Versions now align directly with the FIRST robotics competition season cycle and the underlying WPILib ecosystem (`2027.0.0` repository plugin, WPILib `2027.0.0-alpha-6`, and OpenCV `2027-4.13.0-3`). This makes compatibility and season targeting immediately clear for FTC and FRC robotics teams. + * **Maven Coordinates**: Group ID and artifact coordinates are updated to: + * Gradle: `org.deltacv.VisionBench:VisionBench:2027.0.0` + * Maven: `org.deltacv.VisionBenchVisionBench2027.0.0` + * Changelog: + * **Rebrand to VisionBench**: + * Renames core simulator module from `EOCV-Sim` to `VisionBench`. + * All visual references across the UI—including the About dialog, onboarding walkthrough dialogs, and crash output screens—now display VisionBench branding. + * Migrates CI/CD build workflows and Maven publish tasks to the VisionBench naming scheme. + * **(Re)Introducing VisionGraph (formerly PaperVision)**: + * Rebrands the node-based visual pipeline editor to **VisionGraph**, with companion plugin packaged as `VisionGraphPlugin-2027.0.0-all.jar`. + * Settings dialog and flags now reflect VisionGraph ("*Focus on VisionGraph Upon Startup*"). + * **Viewport FPS Meter Toggle**: + * Adds a configuration option in settings (`showFpsMeter`) to toggle the visibility of the FPS counter overlay in the viewport. + * Viewport renderer (`SwingOpenCvViewport`, `OpenCvViewRenderer`) updated to respect `setFpsMeterEnabled`. + * **Embedded Plugins Resource Loading**: + * Adds `embedded_plugins` resource directory structure, allowing plugin JARs bundled within application resources to be automatically discovered, unpacked, and loaded by `PluginManager` during startup. + * Internal changes: + * Replaces generated `Build.java` with a Gradle-generated `EOCVSimBuildInfo.json` resource loaded dynamically via `BuildInfo.kt`. + * Upgrades build pipeline dependencies to `WPILibRepositoriesPlugin 2027.0.0`, WPILib `2027.0.0-alpha-6`, and OpenCV `2027-4.13.0-3`. + * Removes the deprecated `PaperVisionShadow` module from the build. + * Bugfixes: + * **SuperAccess Daemon Thread Safety**: Adds coroutine `Mutex` locking to `SuperAccessDaemonClient` during daemon initialization to eliminate race conditions during concurrent permission requests. + * **Plugin Security Cache Handling**: Fixes uncaught exceptions when reading malformed or corrupted authorities cache files. + * **Build Info Task Ordering**: Fixes Gradle task dependencies for `writeBuildInfoJson` to ensure reliable build metadata generation prior to packaging. + * **Crash Dialog Decoupling**: Decouples the crash report dialog from the main window hierarchy and removes modal blocking to prevent UI lockups during uncaught exception handling. ## [v4.2.0 - Lifecycle & Platform Architecture Rework](https://github.com/deltacv/EOCV-Sim/releases/tag/v4.2.0) diff --git a/TeamCode/build.gradle b/TeamCode/build.gradle index 78b536d2..bea07cd3 100644 --- a/TeamCode/build.gradle +++ b/TeamCode/build.gradle @@ -5,13 +5,18 @@ plugins { apply from: '../build.common.gradle' dependencies { - api project(':EOCV-Sim') + api project(':VisionBench') implementation "org.jetbrains.kotlin:kotlin-stdlib" } tasks.register('runSim', JavaExec) { dependsOn 'classes' - dependsOn ':EOCV-Sim:processNativesResources' + dependsOn ':VisionBench:processNativesResources' + dependsOn ':VisionBench:processEmbeddedPluginsResources' + mainClass = 'com.github.serivesmejia.eocvsim.Main' - classpath = sourceSets.main.runtimeClasspath + project(':EOCV-Sim').sourceSets.natives.output + + classpath = sourceSets.main.runtimeClasspath + + project(':VisionBench').sourceSets.natives.output + + project(':VisionBench').sourceSets.embeddedPlugins.output } \ No newline at end of file diff --git a/Vision/build.gradle b/Vision/build.gradle index 43266026..c79e4e20 100644 --- a/Vision/build.gradle +++ b/Vision/build.gradle @@ -2,7 +2,7 @@ plugins { id 'kotlin' id 'signing' id 'org.photonvision.tools.WpilibTools' - id "com.vanniktech.maven.publish" version "0.30.0" + id "com.vanniktech.maven.publish" } apply from: '../build.common.gradle' diff --git a/Vision/src/main/java/org/deltacv/vision/external/gui/gui/SwingOpenCvViewport.kt b/Vision/src/main/java/org/deltacv/vision/external/gui/gui/SwingOpenCvViewport.kt index 48e3b6cc..cc12e63e 100644 --- a/Vision/src/main/java/org/deltacv/vision/external/gui/gui/SwingOpenCvViewport.kt +++ b/Vision/src/main/java/org/deltacv/vision/external/gui/gui/SwingOpenCvViewport.kt @@ -155,7 +155,9 @@ class SwingOpenCvViewport( } } - override fun setFpsMeterEnabled(enabled: Boolean) {} + override fun setFpsMeterEnabled(enabled: Boolean) { + renderer.setFpsMeterEnabled(enabled) + } override fun resume() { synchronized(syncObj) { diff --git a/Vision/src/main/java/org/openftc/easyopencv/OpenCvViewRenderer.java b/Vision/src/main/java/org/openftc/easyopencv/OpenCvViewRenderer.java index feeaae5f..90f44e18 100644 --- a/Vision/src/main/java/org/openftc/easyopencv/OpenCvViewRenderer.java +++ b/Vision/src/main/java/org/openftc/easyopencv/OpenCvViewRenderer.java @@ -312,6 +312,12 @@ public void setRenderingPolicy(OpenCvCamera.ViewportRenderingPolicy policy) public void renderPaused(Canvas canvas) { + if (!fpsMeterEnabled) + { + canvas.drawColor(PAUSED_COLOR); + return; + } + canvas.drawColor(PAUSED_COLOR); Rect rect = createRect( diff --git a/EOCV-Sim/build.gradle b/VisionBench/build.gradle similarity index 67% rename from EOCV-Sim/build.gradle rename to VisionBench/build.gradle index cea3b184..6118e226 100644 --- a/EOCV-Sim/build.gradle +++ b/VisionBench/build.gradle @@ -1,3 +1,4 @@ +import groovy.json.JsonOutput import io.github.fvarrui.javapackager.gradle.PackageTask import java.time.LocalDateTime @@ -8,20 +9,54 @@ plugins { id 'com.gradleup.shadow' id 'org.photonvision.tools.WpilibTools' id 'signing' - id "com.vanniktech.maven.publish" version "0.30.0" + id "com.vanniktech.maven.publish" id 'io.github.fvarrui.javapackager.plugin' + id "de.undercouch.download" version "5.7.0" } apply from: '../build.common.gradle' ext.kotest_version = '5.7.2' -def generatedSourcesDir = layout.buildDirectory.dir("generated/sources/buildinfo/java/main") +def generatedResourcesDirProvider = layout.buildDirectory.dir("generated/resources/buildinfo/main") + +tasks.register('writeBuildInfoJson') { + outputs.dir(generatedResourcesDirProvider) + + doLast { + String date = DateTimeFormatter.ofPattern("yyyy-M-d hh:mm:ss") + .format(LocalDateTime.now()) + + def outputDir = generatedResourcesDirProvider.get().asFile + outputDir.mkdirs() + + def buildInfo = [ + versionString : "$version", + standardVersionString: "$standardVersion", + buildDate : date, + isDev : version.toString().contains("dev"), + packagePlatform : "${wpilibTools.currentPlatform.platformName}", + opencvVersion : "$opencvVersion", + paperVisionVersion : "$paperVisionVersion" + ] + + def versionFile = new File(outputDir, "EOCVSimBuildInfo.json") + + versionFile.text = + JsonOutput.prettyPrint( + JsonOutput.toJson(buildInfo) + ) + System.lineSeparator() + } +} + +def generatedResourcesDir = files( + generatedResourcesDirProvider +).builtBy(tasks.named("writeBuildInfoJson")) sourceSets { main { - java { - srcDirs += generatedSourcesDir + resources { + srcDir(generatedResourcesDir) } } @@ -31,6 +66,12 @@ sourceSets { } } + embeddedPlugins { + resources { + srcDir(layout.buildDirectory.dir("generated/embeddedPlugins")) + } + } + natives {} } @@ -44,6 +85,32 @@ components.java { } } +def embeddedPluginsDir = + layout.buildDirectory.dir("generated/embeddedPlugins/embedded_plugins") + +tasks.register("downloadPaperVisionPlugin", Download) { + doFirst { + delete fileTree(embeddedPluginsDir.get().asFile) { + include "PaperVisionPlugin.jar" + include "VisionGraphPlugin-*.jar" + exclude "VisionGraphPlugin-${paperVisionVersion}.jar" + } + } + + src paperVisionPluginUrl + dest embeddedPluginsDir.map { it.file("VisionGraphPlugin-${paperVisionVersion}.jar") } + + overwrite false + onlyIfModified true + retries 3 + + inputs.property("paperVisionVersion", paperVisionVersion) +} + +tasks.named("processEmbeddedPluginsResources") { + dependsOn("downloadPaperVisionPlugin") +} + shadowJar { mergeServiceFiles() archiveClassifier.set(wpilibTools.currentPlatform.platformName) @@ -51,6 +118,7 @@ shadowJar { from(sourceSets.main.output) from(sourceSets.bootstrap.output) from(sourceSets.natives.output) + from(sourceSets.embeddedPlugins.output) manifest { attributes( @@ -137,8 +205,8 @@ dependencies { implementation wpilibTools.deps.wpilibJava("wpimath") wpilibNatives wpilibTools.deps.wpilib("wpimath") - // we don't use this at all... But if we don't have it in the classpath, - // we can't use WPILib's Geometry classes for apriltags. + // we don't use this directly... but we need this in the classpath + // for wpilib's geometry classes to work, used for apriltags implementation "us.hebi.quickbuf:quickbuf-runtime:$quickbufVersion" implementation "org.slf4j:slf4j-api:$slf4j_version" @@ -171,47 +239,7 @@ dependencies { implementation 'org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-depchain:3.3.3' implementation 'org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-impl-maven-archive:3.3.2' - implementation('org.deltacv.visionloop:streaming:1.2.9') { transitive = false } -} - -tasks.register('writeBuildClassJava') { - outputs.dir(generatedSourcesDir) - - doLast { - String date = DateTimeFormatter.ofPattern("yyyy-M-d hh:mm:ss").format(LocalDateTime.now()) - - def packageStr = "com.github.serivesmejia.eocvsim" - def packagePath = packageStr.replace('.', '/') - - def outputDir = file("${generatedSourcesDir.get().asFile}/$packagePath") - outputDir.mkdirs() - - def versionFile = file("${outputDir}/Build.java") - - versionFile.text = """package $packageStr; - -/* - * Autogenerated file! Do not manually edit this file, as - * it is regenerated any time the build task is run. - * - * Based from PhotonVision PhotonVersion generator task - */ -@SuppressWarnings("ALL") -public final class Build { - public static final String versionString = "$version"; - public static final String standardVersionString = "$standardVersion"; - public static final String buildDate = "$date"; - public static final boolean isDev = ${version.contains("dev")}; - public static final String packagePlatform = "${wpilibTools.currentPlatform.platformName}"; - - public static final String opencvVersion = "$opencvVersion"; - public static final String paperVisionVersion = "$papervision_version"; -} -""" + implementation('org.deltacv.visionloop:streaming:1.2.9') { + transitive = false } -} - -tasks.matching { it.name in ["compileJava", "compileKotlin", "sourcesJar"] } - .configureEach { - dependsOn writeBuildClassJava - } \ No newline at end of file +} \ No newline at end of file diff --git a/EOCV-Sim/src/bootstrap/java/com/github/serivesmejia/eocvsim/Bootstrap.java b/VisionBench/src/bootstrap/java/com/github/serivesmejia/eocvsim/Bootstrap.java similarity index 100% rename from EOCV-Sim/src/bootstrap/java/com/github/serivesmejia/eocvsim/Bootstrap.java rename to VisionBench/src/bootstrap/java/com/github/serivesmejia/eocvsim/Bootstrap.java diff --git a/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/BuildInfo.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/BuildInfo.kt new file mode 100644 index 00000000..59a5601c --- /dev/null +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/BuildInfo.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2026 Sebastian Erives + * Licensed under the MIT License. + */ + +package com.github.serivesmejia.eocvsim + +import com.github.serivesmejia.eocvsim.util.serialization.JacksonJsonSupport + +/** + * Runtime build metadata loaded from the generated JSON resource. + * + * The Gradle build writes `EOCVSimBuildInfo.json` into the main resources + * output, and this object reads it lazily at runtime so no source files need + * to be regenerated on no-op builds. + */ +object BuildInfo { + + private const val RESOURCE_PATH = "/EOCVSimBuildInfo.json" + + private data class BuildInfoDto( + val versionString: String, + val standardVersionString: String, + val buildDate: String, + val isDev: Boolean, + val packagePlatform: String, + val opencvVersion: String, + val paperVisionVersion: String + ) + + private val metadata: BuildInfoDto by lazy(LazyThreadSafetyMode.PUBLICATION) { + loadMetadata() + } + + private fun loadMetadata(): BuildInfoDto { + val stream = BuildInfo::class.java.getResourceAsStream(RESOURCE_PATH) + ?: throw IllegalStateException("Missing build metadata resource '$RESOURCE_PATH'. Was the project built with the generated JSON resource enabled?") + + stream.use { + return try { + JacksonJsonSupport.persistenceMapper.readValue(it, BuildInfoDto::class.java) + } catch (ex: Exception) { + throw IllegalStateException("Failed to read build metadata from '$RESOURCE_PATH'", ex) + } + } + } + + val VERSION_STRING: String + get() = metadata.versionString + + val STANDARD_VERSION_STRING: String + get() = metadata.standardVersionString + + val BUILD_DATE: String + get() = metadata.buildDate + + val IS_DEV: Boolean + get() = metadata.isDev + + val PACKAGE_PLATFORM: String + get() = metadata.packagePlatform + + val OPENCV_VERSION: String + get() = metadata.opencvVersion + + val PAPER_VISION_VERSION: String + get() = metadata.paperVisionVersion + + // Backwards-compatible aliases for existing call sites and any external code. + val versionString: String get() = VERSION_STRING + val standardVersionString: String get() = STANDARD_VERSION_STRING + val buildDate: String get() = BUILD_DATE + val isDev: Boolean get() = IS_DEV + val packagePlatform: String get() = PACKAGE_PLATFORM + val opencvVersion: String get() = OPENCV_VERSION + val paperVisionVersion: String get() = PAPER_VISION_VERSION +} diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/EOCVSim.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/EOCVSim.kt similarity index 93% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/EOCVSim.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/EOCVSim.kt index 141651ff..bbb26316 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/EOCVSim.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/EOCVSim.kt @@ -24,17 +24,13 @@ import com.github.serivesmejia.eocvsim.util.io.EOCVSimFolder import com.github.serivesmejia.eocvsim.util.orchestration.Orchestrator import com.github.serivesmejia.eocvsim.workspace.WorkspaceManager import com.qualcomm.robotcore.eventloop.opmode.OpModePipelineHandler +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.swing.Swing import org.deltacv.common.pipeline.PipelineStatisticsCalculator import org.deltacv.common.util.ParsedVersion import org.deltacv.common.util.loggerFor -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancel -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.swing.Swing +import org.deltacv.eocvsim.plugin.loader.PluginManager import org.koin.core.component.KoinComponent import org.koin.core.component.inject import org.koin.core.qualifier.named @@ -55,8 +51,8 @@ import kotlin.system.exitProcess class EOCVSim : KoinComponent { companion object { - const val VERSION = Build.versionString - const val STANDARD_VERSION = Build.standardVersionString + @JvmField val VERSION = BuildInfo.VERSION_STRING + @JvmField val STANDARD_VERSION = BuildInfo.STANDARD_VERSION_STRING val PARSED_VERSION = ParsedVersion(STANDARD_VERSION) @@ -94,7 +90,7 @@ class EOCVSim : KoinComponent { val configManager: ConfigManager by inject() val inputSourceManager: InputSourceManager by inject() - val pluginManager: org.deltacv.eocvsim.plugin.loader.PluginManager by inject() + val pluginManager: PluginManager by inject() val recordingManager: RecordingManager by inject() val dialogFactory: DialogFactory by inject() @@ -196,7 +192,7 @@ class EOCVSim : KoinComponent { val crashHeader = """ Failed to load one or more WPILib native libraries during initialization. - This EOCV-Sim package is intended for ${Build.packagePlatform}. + This EOCV-Sim package is intended for ${BuildInfo.PACKAGE_PLATFORM}. Please verify that you are running the correct build. Additional details are available in the crash report below. @@ -227,8 +223,8 @@ class EOCVSim : KoinComponent { // so we show it here if the user hasn't seen it yet dialogFactory.createIAmAPaperVision(false) } else if(config.flags["prefersPaperVision"] == true) { - // if the user prefers PaperVision, switch to it upon start up - val indexOfTab = visualizer.sidebarPanel.indexOfTab("PaperVision") + // if the user prefers VisionGraph, switch to it upon start up + val indexOfTab = visualizer.sidebarPanel.indexOfTab("VisionGraph") if(indexOfTab >= 0) { visualizer.sidebarPanel.selectedIndex = indexOfTab } @@ -312,6 +308,7 @@ class EOCVSim : KoinComponent { orchestrator.changePhase(Orchestrator.Phase.RUN) while (!eocvSimThread.isInterrupted && !destroying) { + //run all pending requested runnables onMainLoop.run() diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/Lifecycle.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/Lifecycle.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/Lifecycle.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/Lifecycle.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/Main.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/Main.kt similarity index 88% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/Main.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/Main.kt index 37f5807a..af40ffa4 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/Main.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/Main.kt @@ -27,7 +27,7 @@ object Main { fun main(args: Array) { System.setProperty("sun.java2d.d3d", "false") System.setProperty("apple.awt.application.appearance", "system") - System.setProperty("apple.awt.application.name", "EasyOpenCV Simulator") + System.setProperty("apple.awt.application.name", "VisionBench") val result = CommandLine( EOCVSimCommandInterface() @@ -45,7 +45,7 @@ object Main { * @see CommandLine * @see EOCVSim.Parameters */ -@CommandLine.Command(name = "eocvsim", mixinStandardHelpOptions = true, version = [Build.versionString]) +@CommandLine.Command(name = "eocvsim", mixinStandardHelpOptions = true, versionProvider = BuildInfoVersionProvider::class) class EOCVSimCommandInterface : Runnable { @CommandLine.Option( @@ -116,3 +116,11 @@ class EOCVSimCommandInterface : Runnable { } } + +/** + * Supplies the simulator version string at runtime for Picocli commands. + */ +class BuildInfoVersionProvider : CommandLine.IVersionProvider { + override fun getVersion(): Array = arrayOf(BuildInfo.VERSION_STRING) +} + diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/Module.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/Module.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/Module.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/Module.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/config/Config.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/config/Config.java similarity index 95% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/config/Config.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/config/Config.java index bb2d2fff..190487b8 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/config/Config.java +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/config/Config.java @@ -21,9 +21,10 @@ public class Config { public volatile PipelineFps pipelineMaxFps = PipelineFps.MEDIUM; public volatile PipelineTimeout pipelineTimeout = PipelineTimeout.MEDIUM; - public volatile boolean pauseOnImages = true; - - public volatile double webcamOpenTimeoutSec = 5.0; + public volatile boolean pauseOnImages = true; + public volatile boolean showFpsMeter = true; + + public volatile double webcamOpenTimeoutSec = 5.0; public volatile double webcamNewFrameTimeoutSec = 3.0; public volatile Size videoRecordingSize = new Size(640, 480); diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/config/ConfigLoader.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/config/ConfigLoader.java similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/config/ConfigLoader.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/config/ConfigLoader.java diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/config/ConfigManager.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/config/ConfigManager.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/config/ConfigManager.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/config/ConfigManager.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/DialogFactory.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/DialogFactory.kt similarity index 98% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/DialogFactory.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/DialogFactory.kt index a3a68516..f51edf41 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/DialogFactory.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/DialogFactory.kt @@ -13,9 +13,8 @@ import com.github.serivesmejia.eocvsim.gui.dialog.source.* import com.github.serivesmejia.eocvsim.input.SourceType import com.github.serivesmejia.eocvsim.plugin.output.PluginOutputHandler import com.github.serivesmejia.eocvsim.util.event.EventHandler -import com.github.serivesmejia.eocvsim.util.exception.handling.CrashReport -import org.deltacv.eocvsim.plugin.loader.PluginManager import kotlinx.coroutines.CoroutineScope +import org.deltacv.eocvsim.plugin.loader.PluginManager import org.koin.core.component.KoinComponent import org.koin.core.component.inject import java.awt.Component @@ -182,7 +181,7 @@ class DialogFactory : KoinComponent { } fun instantiateCrashReport(crash: String?, headerText: String? = null) = - CrashReportOutput(frame, crash ?: "", headerText) + CrashReportOutput(crash ?: "", headerText) fun createCrashReport(crash: String?, headerText: String? = null) { invokeLater { instantiateCrashReport(crash, headerText) } diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/EOCVSimIconLibrary.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/EOCVSimIconLibrary.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/EOCVSimIconLibrary.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/EOCVSimIconLibrary.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/IconDelegate.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/IconDelegate.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/IconDelegate.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/IconDelegate.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/Icons.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/Icons.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/Icons.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/Icons.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/Visualizer.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/Visualizer.kt similarity index 97% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/Visualizer.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/Visualizer.kt index 376c3d8e..f21733d5 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/Visualizer.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/Visualizer.kt @@ -6,7 +6,7 @@ package com.github.serivesmejia.eocvsim.gui import com.formdev.flatlaf.FlatLaf -import com.github.serivesmejia.eocvsim.Build +import com.github.serivesmejia.eocvsim.BuildInfo import com.github.serivesmejia.eocvsim.LifecycleSignal import com.github.serivesmejia.eocvsim.LifecycleSignal.Destroy.Reason import com.github.serivesmejia.eocvsim.config.ConfigManager @@ -78,7 +78,7 @@ class Visualizer : PhaseOrchestrableBase(), KoinComponent { private set private val fpsMeterDescriptor: String - get() = "deltacv EOCV-Sim v" + Build.standardVersionString + if (Build.isDev) "-dev" else "" + get() = "deltacv VisionBench v" + BuildInfo.STANDARD_VERSION_STRING + if (BuildInfo.IS_DEV) "-dev" else "" @JvmField val viewport = SwingOpenCvViewport(Size(1080.0, 720.0), fpsMeterDescriptor) @@ -111,7 +111,7 @@ class Visualizer : PhaseOrchestrableBase(), KoinComponent { lateinit var tunerCollapsible: CollapsiblePanelX private set - private var title = "EasyOpenCV Simulator v" + Build.standardVersionString + private var title = "VisionBench v" + BuildInfo.STANDARD_VERSION_STRING private var titleMsg = "No pipeline" private var beforeTitleMsg = "" @@ -141,7 +141,7 @@ class Visualizer : PhaseOrchestrableBase(), KoinComponent { Icons.setDark(FlatLaf.isLafDark()) - if (Build.isDev) { + if (BuildInfo.IS_DEV) { title += "-dev " } @@ -155,6 +155,7 @@ class Visualizer : PhaseOrchestrableBase(), KoinComponent { viewport.init() viewport.dark = FlatLaf.isLafDark() + viewport.setFpsMeterEnabled(configManager.config.showFpsMeter) colorPicker = ColorPicker(viewport) @@ -208,7 +209,7 @@ class Visualizer : PhaseOrchestrableBase(), KoinComponent { frame.size = Dimension(780, 645) frame.minimumSize = frame.size - frame.title = "EasyOpenCV Simulator - No Pipeline" + frame.title = "VisionBench - No Pipeline" frame.defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE @@ -292,6 +293,7 @@ class Visualizer : PhaseOrchestrableBase(), KoinComponent { override suspend fun run() { } private fun registerListeners() { + frame.addWindowListener(object : WindowAdapter() { override fun windowClosing(e: WindowEvent) { lifecycleChannel.trySend(LifecycleSignal.Destroy(Reason.USER_REQUESTED)) @@ -402,7 +404,7 @@ class Visualizer : PhaseOrchestrableBase(), KoinComponent { dialogFactory.createInformation( frame, "Runtime pipeline builds are not supported on this JVM", - "For further info, check the EOCV-Sim docs", + "For further info, check the VisionBench docs", "Operation failed" ) } diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/EnumComboBox.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/EnumComboBox.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/EnumComboBox.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/EnumComboBox.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/FileSelector.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/FileSelector.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/FileSelector.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/FileSelector.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/SizeFields.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/SizeFields.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/SizeFields.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/input/SizeFields.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/ColorPicker.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/ColorPicker.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/ColorPicker.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/ColorPicker.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanelConfig.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanelConfig.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanelConfig.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanelConfig.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanelOptions.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanelOptions.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanelOptions.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/TunableFieldPanelOptions.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableComboBox.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableComboBox.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableComboBox.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableComboBox.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableSlider.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableSlider.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableSlider.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableSlider.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableTextField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableTextField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableTextField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/tuner/element/TunableTextField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/CreateSourcePanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/CreateSourcePanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/CreateSourcePanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/CreateSourcePanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/InputSourceDropTarget.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/InputSourceDropTarget.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/InputSourceDropTarget.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/InputSourceDropTarget.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/SidebarPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/SidebarPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/SidebarPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/SidebarPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/TelemetryPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/TelemetryPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/TelemetryPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/TelemetryPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/TopMenuBar.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/TopMenuBar.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/TopMenuBar.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/TopMenuBar.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModeControlsPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModeControlsPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModeControlsPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModeControlsPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModePopupPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModePopupPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModePopupPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModePopupPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModeSelectorPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModeSelectorPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModeSelectorPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/OpModeSelectorPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/SidebarOpModeTabPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/SidebarOpModeTabPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/SidebarOpModeTabPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/opmode/SidebarOpModeTabPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/PipelineSelectorButtonsPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/PipelineSelectorButtonsPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/PipelineSelectorButtonsPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/PipelineSelectorButtonsPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/PipelineSelectorPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/PipelineSelectorPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/PipelineSelectorPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/PipelineSelectorPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/SidebarPipelineTabPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/SidebarPipelineTabPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/SidebarPipelineTabPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/SidebarPipelineTabPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/SourceSelectorPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/SourceSelectorPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/SourceSelectorPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/component/visualizer/pipeline/SourceSelectorPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/About.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/About.kt similarity index 98% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/About.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/About.kt index 3f129111..154bf538 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/About.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/About.kt @@ -55,7 +55,7 @@ class About : KoinComponent { icon.alignmentX = Component.CENTER_ALIGNMENT icon.border = BorderFactory.createEmptyBorder(10, 10, 10, 10) - val appInfo = JLabel("EasyOpenCV Simulator v" + EOCVSim.VERSION) + val appInfo = JLabel("VisionBench v" + EOCVSim.VERSION) appInfo.font = appInfo.font.deriveFont(appInfo.font.style or Font.BOLD) // set font to bold val appInfoLogo = JPanel(FlowLayout()) diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Configuration.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Configuration.kt similarity index 91% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Configuration.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Configuration.kt index 5221e52f..bfe8e250 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Configuration.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Configuration.kt @@ -39,9 +39,10 @@ class Configuration : KoinComponent { private val themeComboBox: JComboBox private val superAccessCheckBox: JCheckBox - private val prefersPaperVisionCheckbox: JCheckBox - private val pauseOnImageCheckBox: JCheckBox - private val webcamOpenTimeoutSpinner: JSpinner + private val prefersPaperVisionCheckbox: JCheckBox + private val fpsMeterCheckBox: JCheckBox + private val pauseOnImageCheckBox: JCheckBox + private val webcamOpenTimeoutSpinner: JSpinner private val webcamNewFrameTimeoutSpinner: JSpinner private val pipelineTimeoutComboBox: EnumComboBox private val pipelineFpsComboBox: EnumComboBox @@ -58,17 +59,21 @@ class Configuration : KoinComponent { superAccessCheckBox = JCheckBox("Auto Accept SuperAccess on Trusted Plugins").apply { isSelected = config.autoAcceptSuperAccessOnTrusted } - prefersPaperVisionCheckbox = JCheckBox("Focus on PaperVision Upon Startup").apply { - isSelected = config.flags["prefersPaperVision"] ?: false - } - val uiPanel = JPanel(GridLayout(3, 1, 1, 8)).apply { - add(JPanel(FlowLayout()).apply { - add(JLabel("Theme: ")) - add(themeComboBox) - }) - add(JPanel(FlowLayout()).apply { add(superAccessCheckBox) }) - add(JPanel(FlowLayout()).apply { add(prefersPaperVisionCheckbox) }) - } + prefersPaperVisionCheckbox = JCheckBox("Focus on VisionGraph Upon Startup").apply { + isSelected = config.flags["prefersPaperVision"] ?: false + } + fpsMeterCheckBox = JCheckBox("Show FPS Meter in Viewport").apply { + isSelected = config.showFpsMeter + } + val uiPanel = JPanel(GridLayout(4, 1, 1, 8)).apply { + add(JPanel(FlowLayout()).apply { + add(JLabel("Theme: ")) + add(themeComboBox) + }) + add(JPanel(FlowLayout()).apply { add(superAccessCheckBox) }) + add(JPanel(FlowLayout()).apply { add(prefersPaperVisionCheckbox) }) + add(JPanel(FlowLayout()).apply { add(fpsMeterCheckBox) }) + } // --- Input Sources Tab --- pauseOnImageCheckBox = JCheckBox("Pause with Image Sources").apply { @@ -173,12 +178,14 @@ class Configuration : KoinComponent { config.webcamNewFrameTimeoutSec = (webcamNewFrameTimeoutSpinner.value as Number).toDouble() config.pipelineTimeout = pipelineTimeoutComboBox.selectedEnum config.pipelineMaxFps = pipelineFpsComboBox.selectedEnum - config.videoRecordingSize = videoRecordingSize.currentSize - config.videoRecordingFps = videoRecordingFpsComboBox.selectedEnum - config.autoAcceptSuperAccessOnTrusted = superAccessCheckBox.isSelected - config.flags["prefersPaperVision"] = prefersPaperVisionCheckbox.isSelected - - configManager.saveToFile() + config.videoRecordingSize = videoRecordingSize.currentSize + config.videoRecordingFps = videoRecordingFpsComboBox.selectedEnum + config.autoAcceptSuperAccessOnTrusted = superAccessCheckBox.isSelected + config.flags["prefersPaperVision"] = prefersPaperVisionCheckbox.isSelected + config.showFpsMeter = fpsMeterCheckBox.isSelected + visualizer.viewport.setFpsMeterEnabled(config.showFpsMeter) + + configManager.saveToFile() if (userSelectedTheme != previousTheme) { dialogFactory.createYesOrNo(dialog, "Applying a new interface theme requires restarting.", "Do you wish to restart now?") { diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/CrashReportOutput.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/CrashReportOutput.kt similarity index 82% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/CrashReportOutput.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/CrashReportOutput.kt index 3824e1b7..a7a659e0 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/CrashReportOutput.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/CrashReportOutput.kt @@ -1,31 +1,24 @@ -/* - * Copyright (c) 2026 Sebastian Erives - * Licensed under the MIT License. - */ - +/* + * Copyright (c) 2026 Sebastian Erives + * Licensed under the MIT License. + */ + package com.github.serivesmejia.eocvsim.gui.dialog -import com.formdev.flatlaf.intellijthemes.FlatArcDarkIJTheme import com.github.serivesmejia.eocvsim.gui.EOCVSimIconLibrary import com.github.serivesmejia.eocvsim.gui.dialog.component.OutputPanel import com.github.serivesmejia.eocvsim.gui.dialog.component.OutputPanel.DefaultBottomButtonsPanel import java.awt.Dimension import java.awt.Font -import javax.swing.BoxLayout -import javax.swing.JDialog -import javax.swing.JFrame -import javax.swing.JLabel -import javax.swing.SwingUtilities -import javax.swing.WindowConstants +import javax.swing.* import kotlin.system.exitProcess class CrashReportOutput( - parent: JFrame?, crashReport: String, headerText: String? = null ){ val output by lazy { - JDialog(parent) + JDialog() } private val reportPanel by lazy { @@ -33,7 +26,6 @@ class CrashReportOutput( } init { - output.isModal = true output.title = "Crash Report" output.layout = BoxLayout(output.contentPane, BoxLayout.Y_AXIS) output.isAlwaysOnTop = true diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/CreateWorkspace.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/CreateWorkspace.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/CreateWorkspace.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/CreateWorkspace.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/FileAlreadyExists.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/FileAlreadyExists.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/FileAlreadyExists.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/FileAlreadyExists.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Output.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Output.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Output.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Output.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/PluginOutput.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/PluginOutput.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/PluginOutput.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/PluginOutput.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/SplashScreen.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/SplashScreen.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/SplashScreen.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/SplashScreen.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/component/OutputPanel.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/component/OutputPanel.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/component/OutputPanel.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/component/OutputPanel.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmA.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmA.kt similarity index 93% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmA.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmA.kt index 659980cf..30b9eff0 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmA.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmA.kt @@ -39,11 +39,11 @@ class IAmA : KoinComponent { dialog.contentPane.layout = GridBagLayout() - val text = """ - Welcome to EOCV-Sim! We'll start with a walkthrough.
- Please select the option that best describes you.

- I am.. - """.trimIndent() + val text = """ + Welcome to VisionBench! We'll start with a walkthrough.
+ Please select the option that best describes you.

+ I am.. + """.trimIndent() dialog.contentPane.add(JLabel("
$text
").apply { font = font.deriveFont(14f) @@ -86,10 +86,10 @@ class IAmA : KoinComponent { } }) - buttonsPanel.add(JButton( - "
Specifically Interested
in PaperVision
", - EOCVSimIconLibrary.icoPaperVision.scaleToFit(60, 60) - ).apply { + buttonsPanel.add(JButton( + "
Specifically Interested
in VisionGraph
", + EOCVSimIconLibrary.icoPaperVision.scaleToFit(60, 60) + ).apply { font = font.deriveFont(14f) horizontalTextPosition = JButton.CENTER verticalTextPosition = JButton.BOTTOM diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAFirstRobotics.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAFirstRobotics.kt similarity index 92% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAFirstRobotics.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAFirstRobotics.kt index 0e0280a8..fb427d38 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAFirstRobotics.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAFirstRobotics.kt @@ -1,8 +1,8 @@ -/* - * Copyright (c) 2026 Sebastian Erives - * Licensed under the MIT License. - */ - +/* + * Copyright (c) 2026 Sebastian Erives + * Licensed under the MIT License. + */ + package com.github.serivesmejia.eocvsim.gui.dialog.iama import com.github.serivesmejia.eocvsim.gui.Visualizer @@ -44,11 +44,11 @@ class IAmAFirstRobotics : KoinComponent { contentsPanel.border = BorderFactory.createEmptyBorder(10, 0, 0, 0) val contentText = """ - Hey FTC teams! EOCV-Sim helps you develop EasyOpenCV pipelines
+ Hello FTC teams! VisionBench helps you develop EasyOpenCV pipelines
without needing to always have the robot hardware at hand.


Work with code identical to the FtcRobotController, iterate with tools like the
variable tuner, and quickly visualize your code changes using workspaces.

- Click on "Open Docs" to learn more about EOCV-Sim and workspaces.
+ Click on "Open Docs" to learn more about VisionBench and workspaces.
""".trimIndent() // Add a descriptive JLabel to the contents panel diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAGeneralPublic.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAGeneralPublic.kt similarity index 89% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAGeneralPublic.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAGeneralPublic.kt index a84a9c0d..e592ed16 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAGeneralPublic.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAGeneralPublic.kt @@ -43,13 +43,13 @@ class IAmAGeneralPublic : KoinComponent { contentsPanel.border = BorderFactory.createEmptyBorder(10, 0, 0, 0) - val contentText = """ - Hey there! EOCV-Sim is a tool that acts as a vision development platform.

- Built from the ground up to use the OpenCV interfaces with Java bindings,
- EOCV-Sim allows you to develop vision pipelines, with tools that help you iterate
- and visualize your code changes quickly, in an easy-to-use interface.

- Click on "Open Docs" to learn more about EOCV-Sim and its features.
- """.trimIndent() + val contentText = """ + Hey there! VisionBench is a tool that acts as a vision development platform.

+ Built from the ground up to use the OpenCV interfaces with Java bindings,
+ VisionBench allows you to develop vision pipelines, with tools that help you iterate
+ and visualize your code changes quickly, in an easy-to-use interface.

+ Click on "Open Docs" to learn more about VisionBench and its features.
+ """.trimIndent() // Add a descriptive JLabel to the contents panel contentsPanel.add( diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAPaperVision.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAPaperVision.kt similarity index 88% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAPaperVision.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAPaperVision.kt index 5b7b1609..41c59252 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAPaperVision.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/iama/IAmAPaperVision.kt @@ -51,30 +51,30 @@ class IAmAPaperVision( } init { - val title = JLabel("
Introducing PaperVision
") - - title.font = title.font.deriveFont(20f) - title.horizontalAlignment = SwingConstants.CENTER - title.alignmentX = JPanel.CENTER_ALIGNMENT // Align horizontally in the BoxLayout - dialog.contentPane.add(title) - - dialog.contentPane.add(Box.createVerticalStrut(5)) - - val gifPanel = JPanel(BorderLayout()) - val label = JLabel(papervisionGif) - gifPanel.add(label, BorderLayout.CENTER) - - gifPanel.alignmentX = JPanel.CENTER_ALIGNMENT // Align the panel in the BoxLayout - dialog.contentPane.add(gifPanel) - - val text = """ - -
- PaperVision is a new pipeline development tool that allows you to create
- your OpenCV algorithms with a visual programming interface, easier than ever before. -
- - """.trimIndent() + val title = JLabel("
Introducing VisionGraph
") + + title.font = title.font.deriveFont(20f) + title.horizontalAlignment = SwingConstants.CENTER + title.alignmentX = JPanel.CENTER_ALIGNMENT // Align horizontally in the BoxLayout + dialog.contentPane.add(title) + + dialog.contentPane.add(Box.createVerticalStrut(5)) + + val gifPanel = JPanel(BorderLayout()) + val label = JLabel(papervisionGif) + gifPanel.add(label, BorderLayout.CENTER) + + gifPanel.alignmentX = JPanel.CENTER_ALIGNMENT // Align the panel in the BoxLayout + dialog.contentPane.add(gifPanel) + + val text = """ + +
+ VisionGraph is a new pipeline development tool that allows you to create
+ your OpenCV algorithms with a visual programming interface, easier than ever before. +
+ + """.trimIndent() dialog.contentPane.add(JLabel(text).apply { font = font.deriveFont(18f) @@ -111,60 +111,60 @@ class IAmAPaperVision( add(Box.createHorizontalStrut(10)) // Add some space between the buttons } - add(JButton("Use PaperVision").apply { - addActionListener { - dialog.dispose() // Close the dialog on click - - val indexOfTab = visualizer.sidebarPanel.indexOfTab("PaperVision") - if(indexOfTab >= 0) { - visualizer.sidebarPanel.selectedIndex = indexOfTab - } else { - JOptionPane.showMessageDialog( - visualizer.frame, - - "PaperVision is not currently available, please check your plugin settings.", - "Warning", - JOptionPane.ERROR_MESSAGE - ) - return@addActionListener - } - - fun openPaperVisionByDefault() { - configManager.config.flags["prefersPaperVision"] = true - } - - if(specificallyInterested) { - openPaperVisionByDefault() - - JOptionPane.showConfirmDialog( - visualizer.frame, - - "From now on, EOCV-Sim will focus on PaperVision upon startup.\nYou can change this in the settings.", - "PaperVision", - JOptionPane.DEFAULT_OPTION, - JOptionPane.INFORMATION_MESSAGE - ) - } else { - JOptionPane.showOptionDialog( - visualizer.frame, - - "Would you like to focus on PaperVision by default?\nThis is useful if you're not interested on the other tools.\nYou can change this in the settings.", - "PaperVision", - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE, - null, - arrayOf("Yes", "No"), - "No" - ).let { - if(it == JOptionPane.YES_OPTION) { - openPaperVisionByDefault() - } else { - configManager.config.flags["prefersPaperVision"] = false - } - } - } - } - }) + add(JButton("Use VisionGraph").apply { + addActionListener { + dialog.dispose() // Close the dialog on click + + val indexOfTab = visualizer.sidebarPanel.indexOfTab("VisionGraph") + if(indexOfTab >= 0) { + visualizer.sidebarPanel.selectedIndex = indexOfTab + } else { + JOptionPane.showMessageDialog( + visualizer.frame, + + "VisionGraph is not currently available, please check your plugin settings.", + "Warning", + JOptionPane.ERROR_MESSAGE + ) + return@addActionListener + } + + fun openPaperVisionByDefault() { + configManager.config.flags["prefersPaperVision"] = true + } + + if(specificallyInterested) { + openPaperVisionByDefault() + + JOptionPane.showConfirmDialog( + visualizer.frame, + + "From now on, VisionBench will focus on VisionGraph upon startup.\nYou can change this in the settings.", + "VisionGraph", + JOptionPane.DEFAULT_OPTION, + JOptionPane.INFORMATION_MESSAGE + ) + } else { + JOptionPane.showOptionDialog( + visualizer.frame, + + "Would you like to focus on VisionGraph by default?\nThis is useful if you're not interested on the other tools.\nYou can change this in the settings.", + "VisionGraph", + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + arrayOf("Yes", "No"), + "No" + ).let { + if(it == JOptionPane.YES_OPTION) { + openPaperVisionByDefault() + } else { + configManager.config.flags["prefersPaperVision"] = false + } + } + } + } + }) border = BorderFactory.createEmptyBorder(0, 10, 10, 10) } diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateCameraSource.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateCameraSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateCameraSource.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateCameraSource.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateHttpSource.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateHttpSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateHttpSource.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateHttpSource.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateImageSource.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateImageSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateImageSource.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateImageSource.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateSourceEx.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateSourceEx.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateSourceEx.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateSourceEx.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateVideoSource.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateVideoSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateVideoSource.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/source/CreateVideoSource.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/theme/Theme.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/theme/Theme.java similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/theme/Theme.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/theme/Theme.java diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/theme/ThemeInstaller.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/theme/ThemeInstaller.java similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/theme/ThemeInstaller.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/theme/ThemeInstaller.java diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/util/GuiUtil.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/util/GuiUtil.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/util/GuiUtil.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/util/GuiUtil.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/util/ThreadedMatPoster.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/util/ThreadedMatPoster.java similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/util/ThreadedMatPoster.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/util/ThreadedMatPoster.java diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/util/WebcamDriver.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/util/WebcamDriver.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/util/WebcamDriver.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/util/WebcamDriver.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/util/icon/PipelineListIconRenderer.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/util/icon/PipelineListIconRenderer.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/util/icon/PipelineListIconRenderer.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/util/icon/PipelineListIconRenderer.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/util/icon/SourcesListIconRenderer.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/util/icon/SourcesListIconRenderer.java similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/gui/util/icon/SourcesListIconRenderer.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/util/icon/SourcesListIconRenderer.java diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/InputSource.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/InputSource.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSource.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceInitializer.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceInitializer.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceInitializer.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceInitializer.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceLoader.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceLoader.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceLoader.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceLoader.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceManager.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceManager.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceManager.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceManager.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/SourceType.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/SourceType.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/SourceType.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/SourceType.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/CameraSource.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/CameraSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/CameraSource.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/CameraSource.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/HttpSource.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/HttpSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/HttpSource.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/HttpSource.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/ImageSource.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/ImageSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/ImageSource.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/ImageSource.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/NullSource.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/NullSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/NullSource.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/NullSource.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/VideoSource.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/VideoSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/VideoSource.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/VideoSource.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/output/RecordingManager.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/output/RecordingManager.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/output/RecordingManager.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/output/RecordingManager.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/output/VideoRecordingSession.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/output/VideoRecordingSession.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/output/VideoRecordingSession.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/output/VideoRecordingSession.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/DefaultPipeline.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/DefaultPipeline.java similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/DefaultPipeline.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/DefaultPipeline.java diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/PipelineManager.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/PipelineManager.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/PipelineManager.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/PipelineManager.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/CompiledPipelineManager.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/CompiledPipelineManager.kt similarity index 95% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/CompiledPipelineManager.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/CompiledPipelineManager.kt index 5cc96957..f594bcd4 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/CompiledPipelineManager.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/CompiledPipelineManager.kt @@ -1,11 +1,11 @@ -/* - * Copyright (c) 2021 Sebastian Erives - * Licensed under the MIT License. - */ - +/* + * Copyright (c) 2021 Sebastian Erives + * Licensed under the MIT License. + */ + package com.github.serivesmejia.eocvsim.pipeline.compiled -import com.github.serivesmejia.eocvsim.Build +import com.github.serivesmejia.eocvsim.BuildInfo import com.github.serivesmejia.eocvsim.gui.DialogFactory import com.github.serivesmejia.eocvsim.gui.dialog.Output import com.github.serivesmejia.eocvsim.pipeline.PipelineManager @@ -49,7 +49,7 @@ class CompiledPipelineManager : PhaseOrchestrableBase(), KoinComponent { val loader = WorkspaceConfigLoader(this) val config = loader.loadWorkspaceConfig() - if(config?.eocvSimVersion != Build.standardVersionString) { + if(config?.eocvSimVersion != BuildInfo.STANDARD_VERSION_STRING) { logger.info("Replacing old default workspace with latest one (version mismatch)") SysUtil.deleteFilesUnder(this) DefaultWorkspaceTemplate.extractTo(this) diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineClassLoader.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineClassLoader.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineClassLoader.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineClassLoader.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineCompiler.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineCompiler.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineCompiler.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineCompiler.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineStandardFileManager.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineStandardFileManager.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineStandardFileManager.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineStandardFileManager.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/handler/PipelineHandler.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/handler/PipelineHandler.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/handler/PipelineHandler.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/handler/PipelineHandler.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/handler/SpecificPipelineHandler.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/handler/SpecificPipelineHandler.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/handler/SpecificPipelineHandler.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/handler/SpecificPipelineHandler.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/instantiator/processor/ProcessorInstantiator.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/instantiator/processor/ProcessorInstantiator.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/instantiator/processor/ProcessorInstantiator.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/instantiator/processor/ProcessorInstantiator.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/instantiator/processor/ProcessorPipeline.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/instantiator/processor/ProcessorPipeline.java similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/instantiator/processor/ProcessorPipeline.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/instantiator/processor/ProcessorPipeline.java diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/util/PipelineExceptionTracker.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/util/PipelineExceptionTracker.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/util/PipelineExceptionTracker.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/util/PipelineExceptionTracker.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/util/PipelineSnapshot.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/util/PipelineSnapshot.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/pipeline/util/PipelineSnapshot.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/util/PipelineSnapshot.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/ConfigApiImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/ConfigApiImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/ConfigApiImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/ConfigApiImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/DialogFactoryApiImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/DialogFactoryApiImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/DialogFactoryApiImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/DialogFactoryApiImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/EOCVSimApiImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/EOCVSimApiImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/EOCVSimApiImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/EOCVSimApiImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/EventHandlerHookApiImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/EventHandlerHookApiImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/EventHandlerHookApiImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/EventHandlerHookApiImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/InputSourceApisImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/InputSourceApisImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/InputSourceApisImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/InputSourceApisImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/PipelineManagerApiImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/PipelineManagerApiImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/PipelineManagerApiImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/PipelineManagerApiImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/SimpleHookApiImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/SimpleHookApiImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/SimpleHookApiImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/SimpleHookApiImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/SwingApisImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/SwingApisImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/SwingApisImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/SwingApisImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VariableTunerApiImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VariableTunerApiImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VariableTunerApiImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VariableTunerApiImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VisualizerApiImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VisualizerApiImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VisualizerApiImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VisualizerApiImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VisualizerComponentsApiImpl.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VisualizerComponentsApiImpl.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VisualizerComponentsApiImpl.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/VisualizerComponentsApiImpl.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/output/VisualPluginOutputHandler.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/output/VisualPluginOutputHandler.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/plugin/output/VisualPluginOutputHandler.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/output/VisualPluginOutputHandler.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableFieldAcceptor.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableFieldAcceptor.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableFieldAcceptor.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableFieldAcceptor.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableFieldRegistry.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableFieldRegistry.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableFieldRegistry.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableFieldRegistry.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableValue.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableValue.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableValue.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunableValue.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunerManager.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunerManager.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunerManager.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/TunerManager.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/exception/CancelTunableFieldAddingException.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/exception/CancelTunableFieldAddingException.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/exception/CancelTunableFieldAddingException.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/exception/CancelTunableFieldAddingException.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/BooleanField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/BooleanField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/BooleanField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/BooleanField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/EnumField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/EnumField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/EnumField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/EnumField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/NumericField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/NumericField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/NumericField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/NumericField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/StringField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/StringField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/StringField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/StringField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/PointField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/PointField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/PointField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/PointField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/RectField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/RectField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/RectField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/RectField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/ScalarField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/ScalarField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/ScalarField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/cv/ScalarField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/DoubleField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/DoubleField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/DoubleField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/DoubleField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/FloatField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/FloatField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/FloatField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/FloatField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/IntegerField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/IntegerField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/IntegerField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/IntegerField.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/LongField.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/LongField.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/LongField.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/tuner/field/numeric/LongField.kt diff --git a/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/ClasspathScan.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/ClasspathScan.kt new file mode 100644 index 00000000..b0cbd4e2 --- /dev/null +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/ClasspathScan.kt @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2021 Sebastian Erives + * Licensed under the MIT License. + */ + +package com.github.serivesmejia.eocvsim.util + +import com.github.serivesmejia.eocvsim.util.orchestration.Orchestrable +import com.github.serivesmejia.eocvsim.util.orchestration.Orchestrator +import com.qualcomm.robotcore.eventloop.opmode.Disabled +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode +import com.qualcomm.robotcore.eventloop.opmode.OpMode +import com.qualcomm.robotcore.util.ElapsedTime +import io.github.classgraph.ClassGraph +import org.deltacv.common.util.loggerForThis +import org.firstinspires.ftc.vision.VisionProcessor +import org.openftc.easyopencv.OpenCvPipeline +import java.net.URI + +class InitClasspathScan : ClasspathScan(), Orchestrable { + override fun wire(orchestrator: Orchestrator) = + orchestrator.register(this) { + phase(Orchestrator.Phase.INIT) { + target { scan(scanForEmbeddedPlugins = true) } + } + } +} + +/** + * Classpath scanner using ClassGraph. + * It scans for OpenCvPipelines, OpModes, VisionProcessors and TunableFields + */ +open class ClasspathScan { + + companion object { + val ignoredPackages = arrayOf( + "java", + "kotlin", + "org.opencv", + "imgui", + "io.github.classgraph", + "org.deltacv", + "com.github.serivesmejia.eocvsim.pipeline", + "org.firstinspires.ftc.vision", + "org.lwjgl", + "org.apache", + "org.codehaus", + "com.google" + ) + } + + val logger by loggerForThis() + + var scanResult: EOCVSimScanResult? = null + private set + + /** + * Perform the classpath scan using ClassGraph, surprisingly fast due to + * the miracles of that library, as it uses bytecode scanning instead of reflection. + * + * This method will scan for OpenCvPipelines, OpModes, VisionProcessors and TunableFields + * @param jarFile the jar file to scan, if null, the classpath will be scanned + * @param classLoader the classloader to use, if null, the system classloader will be used + * @param addProcessorsAsPipelines if true, VisionProcessors will be wrapped as pipelines + */ + @Suppress("UNCHECKED_CAST") + fun scan( + jarFile: String? = null, + classLoader: ClassLoader? = null, + addProcessorsAsPipelines: Boolean = true, + scanForEmbeddedPlugins: Boolean = false + ): EOCVSimScanResult { + val timer = ElapsedTime() + val classGraph = ClassGraph() + .enableClassInfo() + // .verbose() + .enableAnnotationInfo() + .rejectPackages(*ignoredPackages) + + if(scanForEmbeddedPlugins) { + classGraph.acceptPaths("/embedded_plugins") + } + + if (jarFile != null) { + classGraph.overrideClasspath("$jarFile!/") + logger.info("Starting to scan for classes in $jarFile...") + } else { + logger.info("Starting to scan classpath...") + } + + if (classLoader != null) { + classGraph.overrideClassLoaders(classLoader) + } + + val pipelineClasses = mutableListOf>() + val embeddedPlugins = mutableListOf() + + classGraph.scan().use { scanResult -> + + logger.info("ClassGraph finished scanning (took ${timer.seconds()}s)") + + // i...don't even know how to name this, sorry, future readers + // but classgraph for some reason does not have a recursive search for subclasses... + fun searchPipelinesOfSuperclass(superclass: String) { + logger.trace("searchPipelinesOfSuperclass: {}", superclass) + + val superclassClazz = if (classLoader != null) { + classLoader.loadClass(superclass) + } else Class.forName(superclass) + + val pipelineClassesInfo = if (superclassClazz.isInterface) + scanResult.getClassesImplementing(superclass) + else scanResult.getSubclasses(superclass) + + for (pipelineClassInfo in pipelineClassesInfo) { + logger.trace("pipelineClassInfo: {}", pipelineClassInfo.name) + + for (pipelineSubclassInfo in pipelineClassInfo.subclasses) { + searchPipelinesOfSuperclass(pipelineSubclassInfo.name) // naming is my passion + } + + if (pipelineClassInfo.isAbstract || pipelineClassInfo.isInterface) { + continue // nope'd outta here + } + + val clazz = if (classLoader != null) { + classLoader.loadClass(pipelineClassInfo.name) + } else Class.forName(pipelineClassInfo.name) + + logger.trace("class {} super {}", clazz.typeName, clazz.superclass.typeName) + + if (!pipelineClasses.contains(clazz) && ReflectUtil.hasSuperclass(clazz, superclassClazz)) { + if (clazz.isAnnotationPresent(Disabled::class.java)) { + logger.debug("Found @Disabled pipeline ${clazz.typeName}") + } else { + logger.info("Found pipeline ${clazz.typeName}") + pipelineClasses.add(clazz) + } + } + } + } + + // start recursive hell + searchPipelinesOfSuperclass(OpenCvPipeline::class.java.name) + + if (jarFile != null) { + // When specifying a jar file, we consequently remove + // EOCV-Sim from the scan classpath, ClassGraph does not know + // that OpMode and LinearOpMode are subclasses of OpenCvPipeline, + // so we have to scan them manually... + searchPipelinesOfSuperclass(OpMode::class.java.name) + searchPipelinesOfSuperclass(LinearOpMode::class.java.name) + } + + if (addProcessorsAsPipelines) { + logger.info("Searching for VisionProcessors...") + searchPipelinesOfSuperclass(VisionProcessor::class.java.name) + } + + logger.info("Found ${pipelineClasses.size} pipelines") + + if (scanForEmbeddedPlugins) { + scanResult + .getResourcesWithExtension("jar") + .filter { it.path.startsWith("embedded_plugins/") } + .forEach { + logger.info("Found embedded plugin: {}", it.path) + embeddedPlugins.add(it.uri) + } + + logger.info("Found {} embedded plugins", embeddedPlugins.size) + } + } + + logger.info("Finished scanning (took ${timer.seconds()}s)") + + this.scanResult = EOCVSimScanResult( + pipelineClasses, embeddedPlugins + ) + + return this.scanResult!! + } + +} + +/** + * Result of the classpath scan + * @param pipelineClasses the found OpenCvPipelines + */ +data class EOCVSimScanResult( + val pipelineClasses: List>, + val embeddedPlugins: List +) diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/CombinedRuntimeLoader.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/CombinedRuntimeLoader.java similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/CombinedRuntimeLoader.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/CombinedRuntimeLoader.java diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/FileFilters.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/FileFilters.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/FileFilters.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/FileFilters.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/LibraryLoader.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/LibraryLoader.java similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/LibraryLoader.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/LibraryLoader.java diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/CompilerProvider.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/CompilerProvider.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/CompilerProvider.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/CompilerProvider.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/DelegatingStandardFileManager.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/DelegatingStandardFileManager.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/DelegatingStandardFileManager.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/DelegatingStandardFileManager.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/JarPacker.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/JarPacker.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/JarPacker.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/compiler/JarPacker.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/MaxActiveContextsException.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/MaxActiveContextsException.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/MaxActiveContextsException.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/MaxActiveContextsException.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReport.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReport.kt similarity index 92% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReport.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReport.kt index cd3a92b3..6335ea91 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReport.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReport.kt @@ -1,12 +1,12 @@ -/* - * Copyright (c) 2021 Sebastian Erives - * Licensed under the MIT License. - */ - +/* + * Copyright (c) 2021 Sebastian Erives + * Licensed under the MIT License. + */ + package com.github.serivesmejia.eocvsim.util.exception.handling +import com.github.serivesmejia.eocvsim.BuildInfo import com.github.serivesmejia.eocvsim.EOCVSim -import com.github.serivesmejia.eocvsim.Build import com.github.serivesmejia.eocvsim.util.StrUtil import com.github.serivesmejia.eocvsim.util.SysUtil import com.github.serivesmejia.eocvsim.util.extension.plus @@ -53,7 +53,7 @@ class CrashReport(causedByException: Throwable, isDummy: Boolean = false) { "Daisy, daisy...", "Oh - I know what I did wrong!", "I blame ESD.", - "You should try PaperVision!", + "You should try VisionGraph!", "Don't be sad. I'll do better next time, I promise!", "Don't be sad, have a hug! <3", "I just don't know what went wrong :(", @@ -61,7 +61,7 @@ class CrashReport(causedByException: Throwable, isDummy: Boolean = false) { "Do not go gentle into that good night...", "Sorry :(", "Surprise! Haha. Well, this is awkward.", - "Hi. I'm EOCV-Sim, and I'm a crashaholic.", + "Hi. I'm VisionBench, and I'm a crashaholic.", "Ooh. Shiny.", "This doesn't make any sense!", "Why is it breaking :(", @@ -78,7 +78,7 @@ class CrashReport(causedByException: Throwable, isDummy: Boolean = false) { private val sb = StringBuilder() init { - val title = " EOCV-Sim v${EOCVSim.VERSION} crash report" + val title = " VisionBench v${EOCVSim.VERSION} crash report" val dashes = "-".repeat(title.length) val topBorder = "/$dashes\\" val bottomBorder = "\\$dashes/" @@ -97,9 +97,9 @@ class CrashReport(causedByException: Throwable, isDummy: Boolean = false) { } val infoSectionLines = listOf( - ": EOCV-Sim info", + ": VisionBench info", " Version: ${EOCVSim.VERSION}", - " Built on: ${Build.buildDate}", + " Built on: ${BuildInfo.BUILD_DATE}", ": System specs", " OS name: $OS_NAME", " OS version: $OS_VERSION", @@ -143,7 +143,6 @@ class CrashReport(causedByException: Throwable, isDummy: Boolean = false) { sb.appendLine(infoSectionDivider).appendLine() - sb.appendLine(": Full log").appendLine() val lastLogFile = EOCVSimFolder.lastLogFile diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReportOutputMain.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReportOutputMain.kt similarity index 76% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReportOutputMain.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReportOutputMain.kt index 48209679..63bcce26 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReportOutputMain.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/CrashReportOutputMain.kt @@ -1,28 +1,21 @@ -/* - * Copyright (c) 2026 Sebastian Erives - * Licensed under the MIT License. - */ - +/* + * Copyright (c) 2026 Sebastian Erives + * Licensed under the MIT License. + */ + package com.github.serivesmejia.eocvsim.util.exception.handling import com.formdev.flatlaf.intellijthemes.FlatArcDarkIJTheme -import com.github.serivesmejia.eocvsim.Build -import com.github.serivesmejia.eocvsim.gui.DialogFactory -import com.github.serivesmejia.eocvsim.gui.Visualizer +import com.github.serivesmejia.eocvsim.BuildInfoVersionProvider import com.github.serivesmejia.eocvsim.gui.dialog.CrashReportOutput import com.github.serivesmejia.eocvsim.util.SysUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import org.koin.core.context.GlobalContext -import org.koin.dsl.module import picocli.CommandLine import java.io.File import javax.swing.SwingUtilities import kotlin.system.exitProcess object CrashReportOutputMain { - @CommandLine.Command(name = "report", mixinStandardHelpOptions = true, version = [Build.versionString]) + @CommandLine.Command(name = "report", mixinStandardHelpOptions = true, versionProvider = BuildInfoVersionProvider::class) private class CrashReportOutputCommandInterface : Runnable { @CommandLine.Option(names = ["-p", "--path"], description = ["Specifies the path where the crash report was saved"]) @JvmField var crashReportPath: String? = null @@ -43,9 +36,9 @@ object CrashReportOutputMain { try { val crashContent = SysUtil.loadFileStr(file) - CrashReportOutput(null, crashContent ?: "") + CrashReportOutput(crashContent ?: "") } catch (e: Exception) { - System.err.println("Failed to display crash report: $ {e.message}") + System.err.println("Failed to display crash report: ${e.message}") e.printStackTrace() exitProcess(1) } diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/EOCVSimUncaughtExceptionHandler.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/EOCVSimUncaughtExceptionHandler.kt similarity index 75% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/EOCVSimUncaughtExceptionHandler.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/EOCVSimUncaughtExceptionHandler.kt index 3b3e36c2..c6bec68e 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/EOCVSimUncaughtExceptionHandler.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/exception/handling/EOCVSimUncaughtExceptionHandler.kt @@ -1,13 +1,12 @@ -/* - * Copyright (c) 2026 Sebastian Erives - * Licensed under the MIT License. - */ - +/* + * Copyright (c) 2026 Sebastian Erives + * Licensed under the MIT License. + */ + package com.github.serivesmejia.eocvsim.util.exception.handling import com.github.serivesmejia.eocvsim.currentMainThread import com.github.serivesmejia.eocvsim.gui.DialogFactory -import com.github.serivesmejia.eocvsim.util.JavaProcess import com.github.serivesmejia.eocvsim.util.event.EventHandler import org.deltacv.common.util.loggerForThis import kotlinx.coroutines.Dispatchers @@ -17,18 +16,16 @@ import kotlinx.coroutines.swing.Swing import org.koin.core.component.KoinComponent import org.koin.core.component.inject import org.koin.core.qualifier.named -import java.lang.Thread.sleep import javax.swing.SwingUtilities import kotlin.system.exitProcess -class EOCVSimUncaughtExceptionHandler private constructor() : Thread.UncaughtExceptionHandler, KoinComponent{ +object EOCVSimUncaughtExceptionHandler : Thread.UncaughtExceptionHandler, KoinComponent { - companion object { - const val MAX_UNCAUGHT_EXCEPTIONS_BEFORE_CRASH = 3 + const val MAX_UNCAUGHT_EXCEPTIONS_BEFORE_CRASH = 3 - @JvmStatic fun register() { - Thread.setDefaultUncaughtExceptionHandler(EOCVSimUncaughtExceptionHandler()) - } + @JvmStatic + fun register() { + Thread.setDefaultUncaughtExceptionHandler(this) } val logger by loggerForThis() @@ -40,7 +37,7 @@ class EOCVSimUncaughtExceptionHandler private constructor() : Thread.UncaughtExc override fun uncaughtException(t: Thread, e: Throwable) { //we don't want the whole app to crash on a simple interrupted exception right? - if(e is InterruptedException) { + if (e is InterruptedException) { logger.warn("Uncaught InterruptedException thrown in Thread ${t.name}, it will be interrupted", e) t.interrupt() return @@ -52,7 +49,7 @@ class EOCVSimUncaughtExceptionHandler private constructor() : Thread.UncaughtExc // Exit if uncaught exception happened in the main thread // since we would be basically in an invalid state if that happened - if(t == currentMainThread || SwingUtilities.isEventDispatchThread() || e !is Exception || uncaughtExceptionsCount > MAX_UNCAUGHT_EXCEPTIONS_BEFORE_CRASH) { + if (t == currentMainThread || SwingUtilities.isEventDispatchThread() || e !is Exception || uncaughtExceptionsCount > MAX_UNCAUGHT_EXCEPTIONS_BEFORE_CRASH) { val file = CrashReport(e).saveCrashReport() logger.warn("If this error persists, open an issue on EOCV-Sim's GitHub attaching the crash report file.") @@ -70,7 +67,7 @@ class EOCVSimUncaughtExceptionHandler private constructor() : Thread.UncaughtExc } else { CrashReport(e).saveCrashReport("lasterror-eocvsim") - //if not, eocv sim might still be working (i.e a crash from a MatPoster thread) + //if not, eocv sim might still be working (e.g a crash from a MatPoster thread) //so we might not need to exit in this point, but we'll need to send a warning //to the user logger.warn("If this error persists, open an issue on EOCV-Sim's GitHub.") diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/io/FileWatcher.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/io/FileWatcher.kt similarity index 94% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/io/FileWatcher.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/io/FileWatcher.kt index 5d44cd57..de8cd272 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/io/FileWatcher.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/io/FileWatcher.kt @@ -1,8 +1,8 @@ -/* - * Copyright (c) 2026 Sebastian Erives - * Licensed under the MIT License. - */ - +/* + * Copyright (c) 2026 Sebastian Erives + * Licensed under the MIT License. + */ + package com.github.serivesmejia.eocvsim.util.io import com.github.serivesmejia.eocvsim.util.event.EventHandler @@ -91,9 +91,9 @@ class FileWatcher( while (running.get()) { val key = try { watchService.take() - } catch (e: ClosedWatchServiceException) { + } catch (_: ClosedWatchServiceException) { break - } catch (e: InterruptedException) { + } catch (_: InterruptedException) { Thread.currentThread().interrupt() break } diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/serialization/JacksonJsonSupport.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/serialization/JacksonJsonSupport.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/serialization/JacksonJsonSupport.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/serialization/JacksonJsonSupport.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/serialization/VideoModeJackson.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/serialization/VideoModeJackson.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/util/serialization/VideoModeJackson.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/util/serialization/VideoModeJackson.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/WorkspaceManager.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/WorkspaceManager.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/WorkspaceManager.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/WorkspaceManager.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/WorkspaceConfig.java b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/WorkspaceConfig.java similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/WorkspaceConfig.java rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/WorkspaceConfig.java diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/WorkspaceConfigLoader.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/WorkspaceConfigLoader.kt similarity index 90% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/WorkspaceConfigLoader.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/WorkspaceConfigLoader.kt index e14c30fc..c3b7e0c3 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/WorkspaceConfigLoader.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/WorkspaceConfigLoader.kt @@ -1,11 +1,11 @@ -/* - * Copyright (c) 2026 Sebastian Erives - * Licensed under the MIT License. - */ - +/* + * Copyright (c) 2026 Sebastian Erives + * Licensed under the MIT License. + */ + package com.github.serivesmejia.eocvsim.workspace.config -import com.github.serivesmejia.eocvsim.Build +import com.github.serivesmejia.eocvsim.BuildInfo import com.github.serivesmejia.eocvsim.util.SysUtil import com.github.serivesmejia.eocvsim.util.serialization.JacksonJsonSupport import org.deltacv.common.util.loggerForThis @@ -47,7 +47,7 @@ class WorkspaceConfigLoader(var workspaceFile: File) { * @param config the workspace configuration to save */ fun saveWorkspaceConfig(config: WorkspaceConfig) { - config.eocvSimVersion = Build.standardVersionString + config.eocvSimVersion = BuildInfo.STANDARD_VERSION_STRING val configStr = JacksonJsonSupport.persistenceMapper.writeValueAsString(config) SysUtil.saveFileStr(workspaceConfigFile, configStr) } diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/VSCodeLauncher.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/VSCodeLauncher.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/VSCodeLauncher.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/VSCodeLauncher.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/WorkspaceTemplate.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/WorkspaceTemplate.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/WorkspaceTemplate.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/WorkspaceTemplate.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/template/DefaultWorkspaceTemplate.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/template/DefaultWorkspaceTemplate.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/template/DefaultWorkspaceTemplate.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/template/DefaultWorkspaceTemplate.kt diff --git a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/template/GradleWorkspaceTemplate.kt b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/template/GradleWorkspaceTemplate.kt similarity index 85% rename from EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/template/GradleWorkspaceTemplate.kt rename to VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/template/GradleWorkspaceTemplate.kt index df7d9f64..44b1e8b3 100644 --- a/EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/template/GradleWorkspaceTemplate.kt +++ b/VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/template/GradleWorkspaceTemplate.kt @@ -5,7 +5,7 @@ package com.github.serivesmejia.eocvsim.workspace.util.template -import com.github.serivesmejia.eocvsim.Build +import com.github.serivesmejia.eocvsim.BuildInfo import com.github.serivesmejia.eocvsim.util.SysUtil import org.deltacv.common.util.loggerForThis import com.github.serivesmejia.eocvsim.workspace.util.WorkspaceTemplate @@ -48,10 +48,10 @@ object GradleWorkspaceTemplate : WorkspaceTemplate() { SysUtil.replaceStrInFile(settingsGradleFile, "\$workspace_name", folder.name) // replace the versions of the eocvsim dependencies in build.gradle to the current ones - // based on the autogenerated Build.java file + // based on the generated build-info JSON loaded by BuildInfo val fileContents = SysUtil.loadFileStr(buildGradleFile) - .replace("\$eocvsim_version", Build.standardVersionString) - .replace("\$opencv_version", Build.opencvVersion) + .replace("\$eocvsim_version", BuildInfo.STANDARD_VERSION_STRING) + .replace("\$opencv_version", BuildInfo.OPENCV_VERSION) SysUtil.saveFileStr(buildGradleFile, fileContents) } diff --git a/EOCV-Sim/src/main/java/com/qualcomm/robotcore/eventloop/opmode/OpModePipelineHandler.kt b/VisionBench/src/main/java/com/qualcomm/robotcore/eventloop/opmode/OpModePipelineHandler.kt similarity index 100% rename from EOCV-Sim/src/main/java/com/qualcomm/robotcore/eventloop/opmode/OpModePipelineHandler.kt rename to VisionBench/src/main/java/com/qualcomm/robotcore/eventloop/opmode/OpModePipelineHandler.kt diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/gui/dialog/SuperAccessRequest.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/gui/dialog/SuperAccessRequest.kt similarity index 96% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/gui/dialog/SuperAccessRequest.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/gui/dialog/SuperAccessRequest.kt index 3b476107..bad917ff 100644 --- a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/gui/dialog/SuperAccessRequest.kt +++ b/VisionBench/src/main/java/org/deltacv/eocvsim/gui/dialog/SuperAccessRequest.kt @@ -27,7 +27,7 @@ class SuperAccessRequest(sourceName: String, reason: String, val untrusted: Bool val panel = JPanel(BorderLayout()) val frame = JDialog() - frame.title = "EOCV-Sim SuperAccess Request" + frame.title = "VisionBench SuperAccess Request" // Create UI components val titleLabel = JLabel("SuperAccess request from $sourceName", JLabel.CENTER) diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/input/VisionInputSource.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/input/VisionInputSource.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/input/VisionInputSource.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/input/VisionInputSource.kt diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/input/VisionInputSourceProvider.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/input/VisionInputSourceProvider.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/input/VisionInputSourceProvider.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/input/VisionInputSourceProvider.kt diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/input/control/CameraSourceControlMap.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/input/control/CameraSourceControlMap.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/input/control/CameraSourceControlMap.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/input/control/CameraSourceControlMap.kt diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/input/control/CameraSourceExposureControl.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/input/control/CameraSourceExposureControl.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/input/control/CameraSourceExposureControl.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/input/control/CameraSourceExposureControl.kt diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/pipeline/StreamableOpenCvPipelineInstantiator.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/pipeline/StreamableOpenCvPipelineInstantiator.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/pipeline/StreamableOpenCvPipelineInstantiator.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/pipeline/StreamableOpenCvPipelineInstantiator.kt diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/loader/EmbeddedPluginLoader.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/EmbeddedPluginLoader.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/loader/EmbeddedPluginLoader.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/EmbeddedPluginLoader.kt diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/loader/FilePluginLoaderImpl.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/FilePluginLoaderImpl.kt similarity index 94% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/loader/FilePluginLoaderImpl.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/FilePluginLoaderImpl.kt index b674186e..0e1d8b16 100644 --- a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/loader/FilePluginLoaderImpl.kt +++ b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/FilePluginLoaderImpl.kt @@ -23,6 +23,8 @@ import org.deltacv.eocvsim.plugin.security.PluginSignatureVerifier import org.deltacv.eocvsim.sandbox.nio.SandboxFileSystem import net.lingala.zip4j.ZipFile import java.io.File +import java.net.URI +import java.net.URL import java.nio.file.Path /** @@ -259,20 +261,20 @@ open class FilePluginLoaderImpl( } class EmbeddedFilePluginLoader( - resourcePath: String, + resource: URL, classpath: List, pluginManager: PluginManager, outputHandler: PluginOutputHandler ) : FilePluginLoaderImpl( - pluginFile = resourcePath.let { + pluginFile = resource.let { // extract to EMBEDDED_PLUGIN_FOLDER val hash = it.hashString val file = EMBEDDED_PLUGIN_FOLDER + File.separator + "$hash.jar" try { - SysUtil.copyFileIs(EmbeddedFilePluginLoader::class.java.getResourceAsStream(it), file, true) + SysUtil.copyFileIs(it.openStream(), file, true) } catch (e: Exception) { - throw InvalidPluginException("Failed to extract embedded plugin from resource path $resourcePath", e) + throw InvalidPluginException("Failed to copy embedded plugin from $resource", e) } file diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginClassLoader.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginClassLoader.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginClassLoader.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginClassLoader.kt diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginManager.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginManager.kt similarity index 84% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginManager.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginManager.kt index 09fab0d6..35726f8a 100644 --- a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginManager.kt +++ b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginManager.kt @@ -5,13 +5,14 @@ package org.deltacv.eocvsim.plugin.loader -import com.github.serivesmejia.eocvsim.Build +import com.github.serivesmejia.eocvsim.BuildInfo import com.github.serivesmejia.eocvsim.LifecycleSignal import com.github.serivesmejia.eocvsim.config.ConfigManager import com.github.serivesmejia.eocvsim.gui.Visualizer import com.github.serivesmejia.eocvsim.plugin.api.impl.EOCVSimApiImpl import com.github.serivesmejia.eocvsim.plugin.output.PluginDialogSignal import com.github.serivesmejia.eocvsim.plugin.output.PluginOutputHandler +import com.github.serivesmejia.eocvsim.util.InitClasspathScan import com.github.serivesmejia.eocvsim.util.event.EventHandler import com.github.serivesmejia.eocvsim.util.orchestration.initDependency import com.github.serivesmejia.eocvsim.util.orchestration.PhaseOrchestrableBase @@ -27,6 +28,7 @@ import org.koin.core.component.KoinComponent import org.koin.core.component.inject import org.koin.core.qualifier.named import java.io.File +import kotlin.getValue import kotlin.properties.Delegates /** @@ -34,7 +36,9 @@ import kotlin.properties.Delegates */ class PluginManager : PhaseOrchestrableBase(), KoinComponent { + private val classpathScan: InitClasspathScan by initDependency(inject()) private val configManager: ConfigManager by initDependency(inject()) + private val visualizer: Visualizer by inject() private val outputHandler: PluginOutputHandler by inject() @@ -171,43 +175,14 @@ class PluginManager : PhaseOrchestrableBase(), KoinComponent { enableTimestamp = System.currentTimeMillis() isEnabled = true - if (_loaders.find { it.pluginInfo.name == "PaperVision" && it.pluginInfo.author == "deltacv" } == null) { - if (PluginManager::class.java.getResourceAsStream("/embedded_plugins/PaperVisionPlugin.jar") != null) { - _loaders.add( - EmbeddedFilePluginLoader( - "/embedded_plugins/PaperVisionPlugin.jar", - listOf(), - this, - outputHandler - ) - ) - - logger.info("Loaded embedded PaperVision from resources") + for(uri in classpathScan.scanResult!!.embeddedPlugins) { + val loader = EmbeddedFilePluginLoader(uri.toURL(), listOf(), this, outputHandler) + if(_loaders.map { it.hash() }.none { it == loader.hash() }) { + _loaders.add(loader) + logger.info("Added $uri from embedded_plugins") } else { - try { - val pluginInfo = PluginInfo( - "PaperVision", - Build.paperVisionVersion, - "deltacv", - "dev@deltacv.org", - "org.deltacv.papervision.plugin.PaperVisionEOCVSimPlugin", - "Create your custom OpenCV algorithms using a user-friendly node editor interface", - true - ) - - @Suppress("UNCHECKED_CAST") - addEmbeddedPlugin( - pluginInfo, - Class.forName("org.deltacv.papervision.plugin.PaperVisionEOCVSimPlugin") as Class, - ) - - logger.info("Loaded embedded PaperVision from built-in class") - } catch(_: ClassNotFoundException) { - logger.info("Embedded PaperVision was not found") - } + logger.warn("Skipped loading '${loader.pluginInfo.nameWithVersionAndAuthor}' from embedded_plugins, already loaded from another source") } - } else { - outputHandler.sendOutputLine("PaperVision plugin is already loaded, skipping embedded plugin.") } loadPlugins() @@ -255,7 +230,7 @@ class PluginManager : PhaseOrchestrableBase(), KoinComponent { } catch (e: Throwable) { outputHandler.sendDialogSignal(PluginDialogSignal.ShowOutput) outputHandler.sendOutputLine("-- Failure loading ${loader.pluginInfo.nameWithVersion} --") - outputHandler.sendOutputLine("'${e.toString()}'") + outputHandler.sendOutputLine("'$e'") logger.error("Failure loading ${loader.pluginInfo.nameWithVersion}", e) diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryManager.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryManager.kt similarity index 96% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryManager.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryManager.kt index 0f587604..bd8cd87e 100644 --- a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryManager.kt +++ b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryManager.kt @@ -194,7 +194,7 @@ class PluginRepositoryManager( ): Boolean { val result = JOptionPane.showOptionDialog( null, - "Plugin \"$pluginName\" is outdated. Latest version is ${latest.version}. Do you want to update? This will restart EOCV-Sim.", + "Plugin \"$pluginName\" is outdated. Latest version is ${latest.version}. Do you want to update? This will restart VisionBench.", "Update Plugin", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryUpdateChecker.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryUpdateChecker.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryUpdateChecker.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryUpdateChecker.kt diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemon.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemon.kt similarity index 96% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemon.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemon.kt index 7f937246..6b743aa1 100644 --- a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemon.kt +++ b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemon.kt @@ -73,7 +73,7 @@ object SuperAccessDaemon { System.setProperty("sun.java2d.d3d", "false") System.setProperty("apple.awt.UIElement", "true") System.setProperty("apple.awt.application.appearance", "system") - System.setProperty("apple.awt.application.name", "EasyOpenCV Simulator - SuperAccess") + System.setProperty("apple.awt.application.name", "VisionBench - SuperAccess") // start websocket client, listen for EOCV-Sim's requests WsClient(args[0].toIntOrNull() ?: throw IllegalArgumentException("Port is not a valid int"), args[1].toBoolean()).connect() @@ -173,7 +173,7 @@ object SuperAccessDaemon { } warning += if(validAuthority != null) { - "

This plugin has been digitally signed by ${validAuthority.name}.
It is a trusted authority in the EOCV-Sim ecosystem." + "

This plugin has been digitally signed by ${validAuthority.name}.
It is a trusted authority in the VisionBench ecosystem." } else if(untrusted) { "

This plugin claims to be made by ${parser.author}, but it has not been digitally signed by them.

Beware of potential security risks.

" } else { diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemonClient.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemonClient.kt similarity index 89% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemonClient.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemonClient.kt index 7bf7294f..9a1ef973 100644 --- a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemonClient.kt +++ b/VisionBench/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemonClient.kt @@ -18,6 +18,8 @@ import java.util.concurrent.Executors import java.util.concurrent.locks.Condition import java.util.concurrent.locks.ReentrantLock import kotlin.concurrent.withLock +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.sync.Mutex typealias ResponseReceiver = (SuperAccessDaemon.SuperAccessResponse) -> Unit typealias ResponseCondition = (SuperAccessDaemon.SuperAccessResponse) -> Boolean @@ -37,6 +39,7 @@ class SuperAccessDaemonClient( private val startLock = ReentrantLock() val startCondition = startLock.newCondition() + private val initMutex = Mutex() private val cacheLock = Any() private val accessCache = mutableMapOf() @@ -48,16 +51,25 @@ class SuperAccessDaemonClient( fun initIfNeeded() { if (isInitialized) return - - server = WsServer(startLock, startCondition, autoacceptOnTrusted) - server!!.start() - startLock.withLock { - startCondition.await() - } + runBlocking { + initMutex.lock() + try { + if (isInitialized) return@runBlocking - logger.info("SuperAccessDaemonClient initialized") - isInitialized = true + server = WsServer(startLock, startCondition, autoacceptOnTrusted) + server!!.start() + + startLock.withLock { + startCondition.await() + } + + logger.info("SuperAccessDaemonClient initialized") + isInitialized = true + } finally { + initMutex.unlock() + } + } } fun sendRequest(request: SuperAccessDaemon.SuperAccessMessage.Request, onResponse: (Boolean) -> Unit) { diff --git a/EOCV-Sim/src/main/java/org/deltacv/eocvsim/sandbox/restrictions/MethodCallByteCodeChecker.kt b/VisionBench/src/main/java/org/deltacv/eocvsim/sandbox/restrictions/MethodCallByteCodeChecker.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/deltacv/eocvsim/sandbox/restrictions/MethodCallByteCodeChecker.kt rename to VisionBench/src/main/java/org/deltacv/eocvsim/sandbox/restrictions/MethodCallByteCodeChecker.kt diff --git a/EOCV-Sim/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/EOCVSimTelemetryImpl.java b/VisionBench/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/EOCVSimTelemetryImpl.java similarity index 100% rename from EOCV-Sim/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/EOCVSimTelemetryImpl.java rename to VisionBench/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/EOCVSimTelemetryImpl.java diff --git a/EOCV-Sim/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/TelemetryInternal.java b/VisionBench/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/TelemetryInternal.java similarity index 100% rename from EOCV-Sim/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/TelemetryInternal.java rename to VisionBench/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/TelemetryInternal.java diff --git a/EOCV-Sim/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/TelemetryTransmissionReceiver.kt b/VisionBench/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/TelemetryTransmissionReceiver.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/TelemetryTransmissionReceiver.kt rename to VisionBench/src/main/java/org/firstinspires/ftc/robotcore/internal/opmode/TelemetryTransmissionReceiver.kt diff --git a/EOCV-Sim/src/main/java/org/openftc/easyopencv/ProcessFrameInternalAccessor.kt b/VisionBench/src/main/java/org/openftc/easyopencv/ProcessFrameInternalAccessor.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/openftc/easyopencv/ProcessFrameInternalAccessor.kt rename to VisionBench/src/main/java/org/openftc/easyopencv/ProcessFrameInternalAccessor.kt diff --git a/EOCV-Sim/src/main/java/org/openftc/easyopencv/TimestampedPipelineHandler.kt b/VisionBench/src/main/java/org/openftc/easyopencv/TimestampedPipelineHandler.kt similarity index 100% rename from EOCV-Sim/src/main/java/org/openftc/easyopencv/TimestampedPipelineHandler.kt rename to VisionBench/src/main/java/org/openftc/easyopencv/TimestampedPipelineHandler.kt diff --git a/EOCV-Sim/src/main/resources/.lock b/VisionBench/src/main/resources/.lock similarity index 100% rename from EOCV-Sim/src/main/resources/.lock rename to VisionBench/src/main/resources/.lock diff --git a/EOCV-Sim/src/main/resources/cache.toml b/VisionBench/src/main/resources/cache.toml similarity index 100% rename from EOCV-Sim/src/main/resources/cache.toml rename to VisionBench/src/main/resources/cache.toml diff --git a/EOCV-Sim/src/main/resources/contributors.txt b/VisionBench/src/main/resources/contributors.txt similarity index 100% rename from EOCV-Sim/src/main/resources/contributors.txt rename to VisionBench/src/main/resources/contributors.txt diff --git a/VisionBench/src/main/resources/embedded_plugins/.gitignore b/VisionBench/src/main/resources/embedded_plugins/.gitignore new file mode 100644 index 00000000..f23b9489 --- /dev/null +++ b/VisionBench/src/main/resources/embedded_plugins/.gitignore @@ -0,0 +1 @@ +*.jar \ No newline at end of file diff --git a/VisionBench/src/main/resources/embedded_plugins/README.md b/VisionBench/src/main/resources/embedded_plugins/README.md new file mode 100644 index 00000000..9f8b2ae6 --- /dev/null +++ b/VisionBench/src/main/resources/embedded_plugins/README.md @@ -0,0 +1,2 @@ +# embedded_plugins folder +Any plugins placed here will be automatically extracted and loaded by the plugin manager. diff --git a/EOCV-Sim/src/main/resources/fonts/JetBrainsMono-Medium.ttf b/VisionBench/src/main/resources/fonts/JetBrainsMono-Medium.ttf similarity index 100% rename from EOCV-Sim/src/main/resources/fonts/JetBrainsMono-Medium.ttf rename to VisionBench/src/main/resources/fonts/JetBrainsMono-Medium.ttf diff --git a/EOCV-Sim/src/main/resources/fonts/LICENSE.txt b/VisionBench/src/main/resources/fonts/LICENSE.txt similarity index 100% rename from EOCV-Sim/src/main/resources/fonts/LICENSE.txt rename to VisionBench/src/main/resources/fonts/LICENSE.txt diff --git a/EOCV-Sim/src/main/resources/fonts/Roboto-Bold.ttf b/VisionBench/src/main/resources/fonts/Roboto-Bold.ttf similarity index 100% rename from EOCV-Sim/src/main/resources/fonts/Roboto-Bold.ttf rename to VisionBench/src/main/resources/fonts/Roboto-Bold.ttf diff --git a/EOCV-Sim/src/main/resources/fonts/Roboto-BoldItalic.ttf b/VisionBench/src/main/resources/fonts/Roboto-BoldItalic.ttf similarity index 100% rename from EOCV-Sim/src/main/resources/fonts/Roboto-BoldItalic.ttf rename to VisionBench/src/main/resources/fonts/Roboto-BoldItalic.ttf diff --git a/EOCV-Sim/src/main/resources/fonts/Roboto-Italic.ttf b/VisionBench/src/main/resources/fonts/Roboto-Italic.ttf similarity index 100% rename from EOCV-Sim/src/main/resources/fonts/Roboto-Italic.ttf rename to VisionBench/src/main/resources/fonts/Roboto-Italic.ttf diff --git a/EOCV-Sim/src/main/resources/fonts/Roboto-Regular.ttf b/VisionBench/src/main/resources/fonts/Roboto-Regular.ttf similarity index 100% rename from EOCV-Sim/src/main/resources/fonts/Roboto-Regular.ttf rename to VisionBench/src/main/resources/fonts/Roboto-Regular.ttf diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_arrow_dropdown.png b/VisionBench/src/main/resources/images/icon/ico_arrow_dropdown.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_arrow_dropdown.png rename to VisionBench/src/main/resources/images/icon/ico_arrow_dropdown.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_cam.png b/VisionBench/src/main/resources/images/icon/ico_cam.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_cam.png rename to VisionBench/src/main/resources/images/icon/ico_cam.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_colorpick.png b/VisionBench/src/main/resources/images/icon/ico_colorpick.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_colorpick.png rename to VisionBench/src/main/resources/images/icon/ico_colorpick.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_colorpick_pointer.png b/VisionBench/src/main/resources/images/icon/ico_colorpick_pointer.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_colorpick_pointer.png rename to VisionBench/src/main/resources/images/icon/ico_colorpick_pointer.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_config.png b/VisionBench/src/main/resources/images/icon/ico_config.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_config.png rename to VisionBench/src/main/resources/images/icon/ico_config.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_eocvsim.ico b/VisionBench/src/main/resources/images/icon/ico_eocvsim.ico similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_eocvsim.ico rename to VisionBench/src/main/resources/images/icon/ico_eocvsim.ico diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_eocvsim.png b/VisionBench/src/main/resources/images/icon/ico_eocvsim.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_eocvsim.png rename to VisionBench/src/main/resources/images/icon/ico_eocvsim.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_letters.png b/VisionBench/src/main/resources/images/icon/ico_eocvsim_letters.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_letters.png rename to VisionBench/src/main/resources/images/icon/ico_eocvsim_letters.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_letters_transparent.png b/VisionBench/src/main/resources/images/icon/ico_eocvsim_letters_transparent.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_letters_transparent.png rename to VisionBench/src/main/resources/images/icon/ico_eocvsim_letters_transparent.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_new.png b/VisionBench/src/main/resources/images/icon/ico_eocvsim_new.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_new.png rename to VisionBench/src/main/resources/images/icon/ico_eocvsim_new.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_new_128.png b/VisionBench/src/main/resources/images/icon/ico_eocvsim_new_128.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_new_128.png rename to VisionBench/src/main/resources/images/icon/ico_eocvsim_new_128.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_new_16.png b/VisionBench/src/main/resources/images/icon/ico_eocvsim_new_16.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_new_16.png rename to VisionBench/src/main/resources/images/icon/ico_eocvsim_new_16.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_new_32.png b/VisionBench/src/main/resources/images/icon/ico_eocvsim_new_32.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_new_32.png rename to VisionBench/src/main/resources/images/icon/ico_eocvsim_new_32.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_new_64.png b/VisionBench/src/main/resources/images/icon/ico_eocvsim_new_64.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_eocvsim_new_64.png rename to VisionBench/src/main/resources/images/icon/ico_eocvsim_new_64.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_ezv.png b/VisionBench/src/main/resources/images/icon/ico_ezv.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_ezv.png rename to VisionBench/src/main/resources/images/icon/ico_ezv.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_firstrobotics.png b/VisionBench/src/main/resources/images/icon/ico_firstrobotics.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_firstrobotics.png rename to VisionBench/src/main/resources/images/icon/ico_firstrobotics.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_flag.png b/VisionBench/src/main/resources/images/icon/ico_flag.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_flag.png rename to VisionBench/src/main/resources/images/icon/ico_flag.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_folder.png b/VisionBench/src/main/resources/images/icon/ico_folder.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_folder.png rename to VisionBench/src/main/resources/images/icon/ico_folder.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_gears.png b/VisionBench/src/main/resources/images/icon/ico_gears.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_gears.png rename to VisionBench/src/main/resources/images/icon/ico_gears.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_hammer.png b/VisionBench/src/main/resources/images/icon/ico_hammer.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_hammer.png rename to VisionBench/src/main/resources/images/icon/ico_hammer.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_img.png b/VisionBench/src/main/resources/images/icon/ico_img.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_img.png rename to VisionBench/src/main/resources/images/icon/ico_img.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_not_started.png b/VisionBench/src/main/resources/images/icon/ico_not_started.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_not_started.png rename to VisionBench/src/main/resources/images/icon/ico_not_started.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_play.png b/VisionBench/src/main/resources/images/icon/ico_play.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_play.png rename to VisionBench/src/main/resources/images/icon/ico_play.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_slider.png b/VisionBench/src/main/resources/images/icon/ico_slider.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_slider.png rename to VisionBench/src/main/resources/images/icon/ico_slider.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_stop.png b/VisionBench/src/main/resources/images/icon/ico_stop.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_stop.png rename to VisionBench/src/main/resources/images/icon/ico_stop.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_stream.png b/VisionBench/src/main/resources/images/icon/ico_stream.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_stream.png rename to VisionBench/src/main/resources/images/icon/ico_stream.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_textbox.png b/VisionBench/src/main/resources/images/icon/ico_textbox.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_textbox.png rename to VisionBench/src/main/resources/images/icon/ico_textbox.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_user.png b/VisionBench/src/main/resources/images/icon/ico_user.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_user.png rename to VisionBench/src/main/resources/images/icon/ico_user.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_vid.png b/VisionBench/src/main/resources/images/icon/ico_vid.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_vid.png rename to VisionBench/src/main/resources/images/icon/ico_vid.png diff --git a/EOCV-Sim/src/main/resources/images/icon/ico_vscode.png b/VisionBench/src/main/resources/images/icon/ico_vscode.png similarity index 100% rename from EOCV-Sim/src/main/resources/images/icon/ico_vscode.png rename to VisionBench/src/main/resources/images/icon/ico_vscode.png diff --git a/EOCV-Sim/src/main/resources/images/papervision.gif b/VisionBench/src/main/resources/images/papervision.gif similarity index 100% rename from EOCV-Sim/src/main/resources/images/papervision.gif rename to VisionBench/src/main/resources/images/papervision.gif diff --git a/EOCV-Sim/src/main/resources/images/ug_0.jpg b/VisionBench/src/main/resources/images/ug_0.jpg similarity index 100% rename from EOCV-Sim/src/main/resources/images/ug_0.jpg rename to VisionBench/src/main/resources/images/ug_0.jpg diff --git a/EOCV-Sim/src/main/resources/images/ug_1.jpg b/VisionBench/src/main/resources/images/ug_1.jpg similarity index 100% rename from EOCV-Sim/src/main/resources/images/ug_1.jpg rename to VisionBench/src/main/resources/images/ug_1.jpg diff --git a/EOCV-Sim/src/main/resources/images/ug_4.jpg b/VisionBench/src/main/resources/images/ug_4.jpg similarity index 100% rename from EOCV-Sim/src/main/resources/images/ug_4.jpg rename to VisionBench/src/main/resources/images/ug_4.jpg diff --git a/EOCV-Sim/src/main/resources/log4j2.xml b/VisionBench/src/main/resources/log4j2.xml similarity index 100% rename from EOCV-Sim/src/main/resources/log4j2.xml rename to VisionBench/src/main/resources/log4j2.xml diff --git a/EOCV-Sim/src/main/resources/log4j2_nofile.xml b/VisionBench/src/main/resources/log4j2_nofile.xml similarity index 100% rename from EOCV-Sim/src/main/resources/log4j2_nofile.xml rename to VisionBench/src/main/resources/log4j2_nofile.xml diff --git a/VisionBench/src/main/resources/opensourcelibs.txt b/VisionBench/src/main/resources/opensourcelibs.txt new file mode 100644 index 00000000..957bcff2 --- /dev/null +++ b/VisionBench/src/main/resources/opensourcelibs.txt @@ -0,0 +1,25 @@ +VisionBench and its source code is distributed under the MIT License + +OpenCV - Under Apache 2.0 License +WPILib - Under BSD 3-Clause License +FTC SDK - Some source code under BSD 3-Clause License +EasyOpenCV - Some source code under MIT License +EOCV-AprilTag-Plugin - API under the MIT License +Skiko - Under Apache 2.0 License +Kotlin stdlib & coroutines - Under Apache 2.0 License +picocli - Under Apache 2.0 License +FlatLaf - Under Apache 2.0 License +ClassGraph - Under MIT License +Jackson - Under Apache 2.0 License +Log4j - Under Apache 2.0 License +SLF4J - Under MIT License +Koin - Under Apache 2.0 License +ECJ - Under Eclipse Public License 2.0 +MigLayout - Under BSD 3-Clause License +Java-WebSocket - Under Apache 2.0 License +zip4j - Under Apache 2.0 License +kotlinx-coroutines - Under Apache 2.0 License +Kotest - Under Apache 2.0 License +ASM - Under BSD 3-Clause License +ShrinkWrap Resolver - Under Apache 2.0 License +QuickBuf - Under Apache 2.0 License \ No newline at end of file diff --git a/EOCV-Sim/src/main/resources/repository.toml b/VisionBench/src/main/resources/repository.toml similarity index 100% rename from EOCV-Sim/src/main/resources/repository.toml rename to VisionBench/src/main/resources/repository.toml diff --git a/EOCV-Sim/src/main/resources/templates/default_workspace.zip b/VisionBench/src/main/resources/templates/default_workspace.zip similarity index 100% rename from EOCV-Sim/src/main/resources/templates/default_workspace.zip rename to VisionBench/src/main/resources/templates/default_workspace.zip diff --git a/EOCV-Sim/src/main/resources/templates/gradle_workspace.zip b/VisionBench/src/main/resources/templates/gradle_workspace.zip similarity index 100% rename from EOCV-Sim/src/main/resources/templates/gradle_workspace.zip rename to VisionBench/src/main/resources/templates/gradle_workspace.zip diff --git a/VisionBench/src/test/kotlin/com/github/serivesmejia/eocvsim/test/CoreTests.kt b/VisionBench/src/test/kotlin/com/github/serivesmejia/eocvsim/test/CoreTests.kt new file mode 100644 index 00000000..038f8755 --- /dev/null +++ b/VisionBench/src/test/kotlin/com/github/serivesmejia/eocvsim/test/CoreTests.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 Sebastian Erives + * Licensed under the MIT License. + */ + +@file:Suppress("UNUSED") + +package com.github.serivesmejia.eocvsim.test + +import com.github.serivesmejia.eocvsim.util.LibraryLoader +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.core.spec.style.StringSpec +import org.opencv.core.Mat +import org.wpilib.vision.apriltag.jni.AprilTagJNI + +class LibrariesTest : StringSpec({ + "Loading Libraries" { + LibraryLoader.loadLibraries() + } + + "Creating a Mat" { + Mat() + } + + "Create AprilTag Detector" { + val handle = AprilTagJNI.createDetector() + assert(handle != 0.toLong()) + } +}) + +class TestingImplementationPlan : DescribeSpec({ + describe("unit testing implementation plan") { + it("covers pure version and compatibility logic in ParsedVersion").config(enabled = false) { + // TODO: Move to Common/src/test/kotlin/org/deltacv/common/util/ParsedVersionSpec.kt + // Verify major/minor/patch parsing, patch defaults, compares across pre-release semantics, + // and rejection of invalid string formats. + } + + it("covers plugin authority cache and TOML serialization safety").config(enabled = false) { + // TODO: Move to Common/src/test/kotlin/org/deltacv/eocvsim/plugin/security/AuthorityFetcherSpec.kt + // Verify: single authority table is not duplicated, timestamp is updated once, invalid TOML is reset, + // cache entries expire after TTL, and duplicate authority names do not re-define the same table. + } + + it("covers plugin repository artifact parsing and dependency checks").config(enabled = false) { + // TODO: Move to EOCV-Sim/src/test/kotlin/org/deltacv/eocvsim/plugin/repository/PluginRepositorySpec.kt + // Verify: parseArtifact handles malformed input, findArtifactRootUrl builds the expected Maven layout, + // checkForUpdates compares current vs latest correctly, and invalid repositories return null. + } + + it("covers file watch filtering and recursive directory registration").config(enabled = false) { + // TODO: Move to EOCV-Sim/src/test/kotlin/com/github/serivesmejia/eocvsim/util/io/FileWatcherSpec.kt + // Verify: extension matching is case-insensitive, recursive watch registration works for nested folders, + // and change callbacks only fire for expected file types. + } + + it("covers the plugin signing and verification pipeline").config(enabled = false) { + // TODO: Move to Common/src/test/kotlin/org/deltacv/eocvsim/plugin/security/PluginSigningSpec.kt + // Verify: parsePem strips PEM wrappers, public key parsing succeeds, signature verification accepts + // matching keys and rejects tampered class data. + } + } +}) \ No newline at end of file diff --git a/build.gradle b/build.gradle index 17d95717..cd3db3c1 100644 --- a/build.gradle +++ b/build.gradle @@ -15,13 +15,17 @@ plugins { id 'java' id 'org.jetbrains.kotlin.jvm' version '2.3.21' apply false id 'com.gradleup.shadow' version '9.3.1' apply false + id "com.vanniktech.maven.publish" version "0.30.0" apply false id 'org.photonvision.tools.WpilibTools' version '4.1.1-photon' id "org.wpilib.WPILibRepositoriesPlugin" version "2027.0.0" } ext { - wpilibVersion = "2027.0.0-alpha-6" - opencvVersion = "2027-4.13.0-3" + paperVisionVersion = "2027.0.0" + paperVisionPluginUrl = "https://github.com/deltacv/VisionGraph/releases/download/v${paperVisionVersion}/VisionGraphPlugin-${paperVisionVersion}-all.jar" + + wpilibVersion = "2027.0.0-alpha-6" + opencvVersion = "2027-4.13.0-3" quickbufVersion = "1.3.3"; kotlin_version = "2.3.21" @@ -29,8 +33,7 @@ ext { koin_version = "4.2.0" slf4j_version = "2.0.16" log4j_version = "2.24.1" - jackson_version = "2.15.2"; - papervision_version = "1.1.0" + jackson_version = "2.15.2" flatlaf_version = "3.5.1" miglayout_version = "11.4.2" @@ -58,8 +61,8 @@ ext { } allprojects { - group 'org.deltacv.EOCV-Sim' - version '4.2.0' + group 'org.deltacv.VisionBench' + version '2027.0.0' apply plugin: 'java' diff --git a/documents/01-overview-and-architecture.md b/documents/01-overview-and-architecture.md new file mode 100644 index 00000000..65a2ae33 --- /dev/null +++ b/documents/01-overview-and-architecture.md @@ -0,0 +1,132 @@ +# Overview and architecture + +## Project purpose + +EOCV-Sim is a desktop simulator for OpenCV-based pipelines, aimed primarily at FTC and robotics development. The problem it solves is straightforward: developers want to write and test OpenCV pipeline logic in a desktop environment without requiring direct hardware execution. The app gives them a Swing UI, a configurable image/camera input stream, a live pipeline runtime, and a developer workspace that can compile and reload user code on demand. + +At a high level the project combines four major ideas: + +- a desktop GUI for viewing pipeline output, +- a runtime that mimics FTC/OpenCV pipeline semantics, +- a workspace model for editable Java source code, +- and an extension model for plugins and optional security-sensitive features. + +## Repository layout + +The repository is split into a few important modules: + +### `../VisionBench/` + +This is the main application module. It contains the desktop runtime, GUI, configuration manager, pipeline engine, workspace logic, plugin integration, and startup lifecycle. This module is the heart of the simulator. + +Key classes and packages include: + +- `Main.kt` — JVM entry point and command bootstrap +- `EOCVSim.kt` — central application lifecycle and startup coordination +- `Module.kt` — Koin dependency graph setup +- `config/` — config persistence and runtime settings +- `gui/` — Swing UI and tool panels +- `pipeline/` — active pipeline management, instantiation, and exception tracking +- `input/` — source loading and frame acquisition +- `workspace/` — workspace scanning, template creation, file watching and build integration +- `plugin/` — repository loading, plugin API, and security workflows + +### `Common/` + +The Common module contains reusable infrastructure: orchestration, shared logger utilities, pipeline statistics, and cross-cutting helpers. It acts as the “glue” layer that keeps the app lifecycle consistent across modules without forcing each subsystem to reinvent common behavior. + +Examples include: + +- lifecycle orchestration classes, +- logging helpers, +- serialization helpers, +- shared pipeline metadata and calculations. + +### `Vision/` + +This module is responsible for the OpenCV rendering pipeline and GUI adapter layer. It wraps lower-level OpenCV drawing and Java Swing display concerns into a desktop-friendly viewport implementation. Most of the actual visible rendering and FPS overlay logic lives here. + +Important classes include: + +- `SwingOpenCvViewport.kt` — desktop Swing-backed viewport implementation +- `OpenCvViewRenderer.java` — canvas renderer and FPS overlay +- supporting FTC/OpenCV wrapper classes in the `external` and `internal` packages + +### `TeamCode/` + +This is a sample area containing FTC-style pipeline examples and test code. It shows how this simulator fits into the FTC ecosystem and how users can author pipelines in a familiar style while running them locally. + +## High-level runtime flow + +The app uses a layered runtime model: + +1. JVM process starts via `Main.kt` +2. Koin creates the dependency graph from `Module.kt` +3. `EOCVSim.start()` proceeds through initialization and startup +4. Config, workspace, plugins, input sources, and GUI are created in dependency order +5. The pipeline manager chooses an active pipeline +6. Input frames are acquired from a source and passed to the active pipeline +7. Output is rendered in the viewport and optionally overlaid with stats +8. The app continues until shutdown or restart + +This is a classic runtime shell with several independent subsystems, rather than one monolithic class doing everything. + +## Orchestration pattern + +The central lifecycle abstraction is the `Orchestrator` and `PhaseOrchestrableBase`. Major subsystems inherit from `PhaseOrchestrableBase`, which gives them a common sequence: + +- initialization +- run phase +- destroy/teardown + +This matters because code depends on other subsystems being ready at the right time. For example, the visualizer should not be created before the config manager is loaded, and the workspace manager should not trigger compilation before the pipeline manager exists. + +Most subsystems therefore participate in the same lifecycle rather than being manually wired ad hoc in a single startup method. + +## Dependency injection and event-driven coordination + +The project uses Koin as its dependency injection system. In `Module.kt`, the app registers services such as: + +- `ConfigManager` +- `WorkspaceManager` +- `PipelineManager` +- `InputSourceManager` +- `TunerManager` — live field inspection and runtime tuning for active pipeline objects +- `PluginManager` +- `CompiledPipelineManager` +- `Visualizer` + +This makes it easy for the code to resolve runtime dependencies without constructing a huge object graph manually. + +The project also makes heavy use of `EventHandler`. Many cross-cutting behaviors are triggered through event subscriptions instead of direct hard coupling, including: + +- pipeline change notifications, +- pipeline exceptions, +- on-main-loop execution, +- source load failures, +- workspace rebuild events, +- plugin output and UI signals. + +This pattern keeps the runtime responsive and reduces the need for tightly coupled object references scattered throughout the codebase. + +The live tuning system is another cross-cutting concern worth noting: `TunerManager` discovers editable fields from the current pipeline via reflection, wires them to Swing controls, and continuously syncs values between the pipeline object and the GUI. This is how the simulator can expose runtime settings like thresholds, blur values, or draw parameters without forcing a full rebuild or restart. + +## OpenCV-first execution model + +Although the app is a desktop Swing application, it is still fundamentally OpenCV-first. The pipeline is the computational core, while the GUI is a presentation layer. The runtime does not merely display images; it feeds them into actual pipeline logic, collects telemetry, allows runtime tuning, and renders the resulting annotated frame back to the viewport. + +This is why the simulator is useful as a development tool: it preserves the actual pipeline execution flow while letting developers inspect and iterate on it in a desktop environment. + +## Design takeaways + +The major architectural idea is that EOCV-Sim is not just a viewer; it is a runtime container for user pipeline code. It manages: + +- config and user settings, +- file-based sources, +- workspace compilation, +- pipeline execution, +- rendering and overlay statistics, +- plugin loading and trust review, +- and a desktop GUI that ties it all together. + +That combination makes the project feel like a small but full-featured robotics development environment rather than a simple demo app. diff --git a/documents/02-main-eocvsim.md b/documents/02-main-eocvsim.md new file mode 100644 index 00000000..833f3d8d --- /dev/null +++ b/documents/02-main-eocvsim.md @@ -0,0 +1,108 @@ +# Main application flow and `EOCVSim` + +## Entry points + +The process starts in `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/Main.kt`. This file is the JVM bootstrap layer. It does things that belong to app startup and platform integration rather than the business logic of the simulator itself, such as: + +- setting Java 2D and desktop environment properties, +- configuring OS-specific app naming for macOS, +- creating the command-line entry structure, +- and exiting with a proper status code when the app is done. + +This is the outer shell of the app. Most of the actual runtime behavior lives elsewhere. + +## The central runtime object + +The true app runtime is `EOCVSim` in `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/EOCVSim.kt`. It is the orchestration hub. The class resolves or owns references to the major subsystems: + +- `ConfigManager` +- `Visualizer` +- `InputSourceManager` +- `PipelineManager` +- `WorkspaceManager` +- `PluginManager` +- `RecordingManager` +- `DialogFactory` +- `TunerManager` +- `Orchestrator` + +The reason this class matters is that it is the place where the application is assembled into a working runtime rather than just a collection of independent libraries. + +## Startup sequence in `EOCVSim.start()` + +`EOCVSim.start()` runs the application boot sequence in a careful order. A simplified flow is: + +1. Validate that the app can claim its lock file, preventing duplicate running instances. +2. Show the splash screen and register the global crash handler. +3. Load required native libraries. +4. Change the orchestrator phase to `INIT` and call `orchestrate()`. +5. Initialize the UI and trigger first-run welcome dialogs when needed. +6. Ensure an input source is selected and persisted. +7. Populate source and pipeline selector lists. +8. Set the default active pipeline. +9. Attach the pipeline output to the viewport. +10. Enable plugins. + +This sequence matters because several subsystems depend on each other. For instance, the visualizer needs the config and input manager to be ready, and the workspace/pipeline systems need the UI to be present before source switching is enabled. + +## `Module.kt` and the dependency graph + +The Koin module in `Module.kt` is how the app wires itself together. It registers singleton components like: + +- `PipelineStatisticsCalculator` +- `ConfigManager` +- `WorkspaceManager` +- `PipelineManager` +- `InputSourceManager` +- `InputSourceInitializer` +- `TunerManager` +- `PluginManager` +- `CompiledPipelineManager` +- `Visualizer` +- `DialogFactory` +- `RecordingManager` +- `Orchestrator` + +This is a good example of the app’s architecture: services are provided centrally and then resolved via injection rather than created manually in many places. + +## Lifecycle and orchestration + +The runtime makes use of the shared `Orchestrator` and `PhaseOrchestrableBase` abstractions. Subsystems are initialized in a consistent order and can be stopped cleanly when the app is shutting down. + +The major phases are conceptually: + +- `INIT` — configure and build runtime state +- `RUN` — let the main loop and runtime run +- `DESTROY` — tear down components and release resources + +This lifecycle approach keeps startup, runtime updates, and shutdown behavior consistent across the application instead of relying on brittle manual ordering. + +## Crash handling and native initialization + +The startup code is protective. It installs `EOCVSimUncaughtExceptionHandler` and is careful about native library loading. If critical libraries are missing or fail to initialize, the app can show a crash report to the user instead of crashing silently. + +That is especially important in a project like this, where native OpenCV and WPILib components are involved. Startup failure is not treated as a simple runtime exception; it is treated as a major environment issue. + +## Main loop coordination + +The app owns a global coroutine scope and a main-loop event handler. This allows the runtime to schedule UI work, pipeline logic, and other state updates without manually synchronizing every background thread. + +The key idea is that the app’s runtime is event-driven: + +- external signals trigger the UI, +- pipeline state changes update the selection panels, +- input sources can fail or time out, +- the viewport can update when a new frame arrives, +- workspace changes can trigger automatic rebuilds. + +This makes the runtime dynamic and resilient, particularly when user code and files are changing while the app is already running. + +## Restart and shutdown behavior + +The app’s lifecycle also supports restart and destroy signals. It can notify the runtime that it should stop, clean up, or restart a subsystem depending on the conditions. This is useful for plugin changes, reinstallations, or major config-driven state refreshes. + +The design is not purely static: the app expects components to be reconfigured and reused in a live environment. + +## Summary + +`EOCVSim` is the runtime coordinator for the whole simulator. It is not the pipeline engine, nor the rendering layer, nor the settings manager alone. It is the architectural center: it assembles the pieces, sequences them in the correct order, coordinates runtime updates, and exposes the full application lifecycle to the rest of the codebase. diff --git a/documents/03-config-and-settings.md b/documents/03-config-and-settings.md new file mode 100644 index 00000000..f4fb68d6 --- /dev/null +++ b/documents/03-config-and-settings.md @@ -0,0 +1,87 @@ +# Configuration and settings + +## Purpose of the config system + +The configuration subsystem is responsible for persistent runtime preferences and defaults. It sits at the boundary between the user-facing simulator settings and the more operational systems such as the input manager, pipeline manager, workspace system, and plugins. + +This subsystem is implemented mainly in: + +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/config/Config.java` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/config/ConfigManager.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/gui/dialog/Configuration.kt` + +## `Config.java`: the settings model + +The central data model is `Config`, a plain Java object with a set of persistent runtime fields. It stores user-visible and app-level preferences such as: + +- `simTheme` — the active UI theme +- `pipelineMaxFps` and `pipelineTimeout` — processing constraints for pipeline execution +- `pauseOnImages` — pause behavior when switching to image sources +- `showFpsMeter` — toggles the viewport overlay +- `webcamOpenTimeoutSec` and `webcamNewFrameTimeoutSec` — camera/source timeouts +- `videoRecordingSize` and `videoRecordingFps` — output recording settings +- `workspacePath` — the default project workspace used by the simulator +- `globalTunableFieldsConfig` — default style and behavior for tunable fields +- `specificTunableFieldConfig` — per-field overrides +- `autoAcceptSuperAccessOnTrusted` — trust/approval behavior for plugins +- `flags` — a dictionary of feature toggles and user state flags + +The class is intentionally simple and serialization-friendly. It is not a framework abstraction; it is the state container the rest of the app reads and writes. + +## `ConfigManager`: loading and saving + +`ConfigManager` is the lifecycle owner for the config. It is responsible for: + +- loading config from the app’s persisted file, +- creating a default config when missing, +- saving the current config back to disk, +- exposing the live object through `config`. + +This manager follows the project’s broader pattern: a top-level runtime service exposes state to the rest of the app via dependency injection, while also handling persistence and validation. + +The typical flow is: + +1. app startup loads the config file, +2. config values are read by the systems that need them, +3. the settings UI updates the live config, +4. the user accepts changes, +5. `saveToFile()` writes everything back to disk. + +## Settings dialog and UX + +The user-facing settings window is `Configuration.kt`. It is the main place where the user edits runtime settings. The dialog organizes settings into categories such as: + +- `Interface` — UI themes, startup preferences, FPS overlay, visible behavior +- `Input Sources` — image/camera settings and timeouts +- `Processing` — pipeline timing and output behavior +- potentially other advanced options tied to workspace and plugin behavior + +The important UX distinction is that the dialog does not mutate the config object immediately in all cases; instead, it gathers user selections and then applies them when the user confirms. This has the benefit of preserving a clean “accept/cancel” flow and avoids accidental mid-edit state changes. + +## Relationship to other subsystems + +The configuration object is a central dependency for many modules. For example: + +- `Visualizer` reads `config.simTheme` and `config.showFpsMeter` to set up the viewport and theme +- `InputSourceManager` reads `pauseOnImages` when selecting image sources +- `PipelineManager` and related logic use timing settings for processing constraints +- plugin trust preferences affect `PluginManager` behavior +- workspace settings influence the default project root and compiler behavior + +This is a good example of the project’s architecture: instead of each subsystem keeping duplicate settings, the app relies on the central config manager as the single source of truth. + +## Important settings and their role + +A few values are especially important in the runtime: + +- `pauseOnImages` — used to pause image sources for single-frame analysis or inspection +- `showFpsMeter` — toggles the live visual statistics overlay in the viewport +- `autoAcceptSuperAccessOnTrusted` — helps trusted plugins work without repeated approval prompts +- `workspacePath` — default root folder for the user workspace +- `flags` — arbitrary feature toggles used for first-run guides, startup preferences, plugin disclaimers, and other user state + +These settings are not “cosmetic only.” They affect the actual behavior of the live simulator. + +## Why this subsystem matters + +The app’s quality as a development tool depends heavily on this settings layer. Without a central config model, the app would constantly scatter preferences across many classes and duplicate logic. By consolidating all user configuration in one model, the project keeps the runtime easier to reason about and easier to save, restore, and expose in the UI. diff --git a/documents/04-gui-and-visualizer.md b/documents/04-gui-and-visualizer.md new file mode 100644 index 00000000..c2a7879a --- /dev/null +++ b/documents/04-gui-and-visualizer.md @@ -0,0 +1,113 @@ +# GUI and visualizer subsystem + +## Purpose and scope + +The GUI subsystem is the desktop shell around the simulator. It is responsible for the user-facing window, viewport display, control panels, dialogs, and interaction points that let a user select sources, choose pipelines, tune variables, and inspect runtime output. + +The main implementation is `Visualizer.kt`, but the subsystem also includes related UI components in packages such as: + +- `gui/component/visualizer/` +- `gui/component/tuner/` +- `gui/dialog/` +- `gui/component/input/` + +This is one of the most visible parts of the app because it is where the actual “simulator” experience is presented. + +## The `Visualizer` class + +`Visualizer` is the main Swing host. It extends `PhaseOrchestrableBase` and participates in the app lifecycle, which means it has explicit init and teardown behavior and is created as a managed runtime component. + +It owns and builds the primary application window, including: + +- the main `JFrame` +- the viewport area where OpenCV output is displayed +- the menu bar and window title +- the sidebar pipeline/opmode tabs +- source selector and pipeline selector panels +- the tuner UI area +- plugin-attached GUIs + +The visualizer gathers runtime dependencies from Koin, including the config manager, input source manager, pipeline manager, workspace manager, and recording manager. + +## Viewport and rendering setup + +The visualizer creates a `SwingOpenCvViewport` from the `Vision` module: + +- `viewport` is instantiated with a default size and descriptor string +- the FPS meter descriptor is used to generate the overlay label text +- the viewport is initialized and styled based on theme +- the FPS meter is enabled or disabled according to config + +This viewport is the place where live image output, pipeline overlay, and timing statistics are visible. It is also the target of the active pipeline’s output publishing. + +## Rendering flow from pipeline to screen + +The render path is one of the most important parts of the system: + +1. the active input source produces a `Mat` +2. the pipeline processes that `Mat` +3. the pipeline manager posts the output to registered output posters +4. the viewport receives those output matrices +5. the viewport renders them to a Swing/Skia canvas +6. if enabled, the FPS meter and timing stats overlay are drawn +7. user pipeline draw hooks can add additional annotations on top + +The render hook is a key concept here. `Visualizer` wires an OpenCv viewport `RenderHook` that calls the active pipeline’s `onDrawFrame()` when initialized. This lets user pipelines annotate the output frame without the pipeline manager needing to coordinate UI drawing directly. + +## Sidebar and source controls + +The app’s UI is built as a collection of stateful panels. The sidebar contains tabs for: + +- pipeline selection +- opmode selection +- other control workflows that may be attached by plugins + +The visualizer creates and holds references to these panel objects: + +- `sidebarPanel` +- `sidebarPipelineTabPanel` +- `sidebarOpModeTabPanel` +- `pipelineSelectorPanel` +- `sourceSelectorPanel` +- `opModeSelectorPanel` +- `tunerCollapsible` + +This is the central user control surface of the app. It lets the user switch between sources and pipelines while watching the model run in real time. + +## Dialogs and modal windows + +The UI relies on `DialogFactory` to centralize modal dialogs. These dialogs cover many runtime actions, including: + +- splash screens and initialization messages, +- welcome screens, +- plugin output, +- about and help dialogs, +- workspace creation, +- config dialogs, +- pipeline output and error windows, +- source-loading errors, +- security review prompts such as SuperAccess approval. + +This keeps the UI logic cleaner and reduces scattered Swing instantiation across the codebase. + +## Event-driven UI behavior + +The visualizer responds to runtime events, not just static UI actions. It listens for state changes like: + +- source initialization errors, +- plugin GUI attachments, +- pipeline changes, +- lifecycle events, +- startup completion. + +This makes the UI feel like a live control surface rather than a static window. It is especially important in a simulator where user code, source files, and plugin behaviors can change at runtime. + +## Theme and lifecycle integration + +The visualizer is also theme-aware. It installs the configured UI theme at initialization time and adapts the viewport’s dark mode state accordingly. It also manages frame title updates, maximize state, taskbar icon behavior, and the close action depending on lifecycle signals. + +This keeps the desktop experience polished while still leaving the low-level rendering and runtime logic in the correct architectural layers. + +## Why the GUI subsystem matters + +The GUI looks like the app’s “front end,” but it is more than just a shell. It is where the simulator makes its main value visible: it gives users a controlled, interactive environment to run, inspect, and tune OpenCV-based workflows. The actual computations still happen in the pipeline and input systems, but the visualizer is the component responsible for exposing them in a usable way. diff --git a/documents/05-pipeline-runtime.md b/documents/05-pipeline-runtime.md new file mode 100644 index 00000000..83f22414 --- /dev/null +++ b/documents/05-pipeline-runtime.md @@ -0,0 +1,314 @@ +# Pipeline runtime subsystem + +## Purpose and scope + +The pipeline runtime is the execution engine of the simulator. It is the subsystem that turns source frames into processed output and makes the app feel like an actual robotics vision playground rather than a static image viewer. + +The pipeline stack is spread across several classes and packages: + +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/PipelineManager.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/CompiledPipelineManager.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineCompiler.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/PipelineClassLoader.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/util/PipelineExceptionTracker.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/util/PipelineSnapshot.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/handler/` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/instantiator/` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/DefaultPipeline.java` + +Broadly speaking, the runtime is responsible for: + +- discovering available pipeline classes, +- selecting a current pipeline, +- instantiating and switching between pipelines, +- processing source frames, +- handling exceptions and telemetry, +- forwarding output to the viewport, +- and supporting warm-reload of compiled user code. + +## The central class: `PipelineManager` + +`PipelineManager` is the main orchestration class. It sits in the center of the subsystem and owns most of the runtime state, event handlers, and pipeline switching logic. It is not the actual algorithm implementation of a pipeline; it is the scheduler and coordinator that makes pipeline objects usable inside the simulator. + +The most important runtime state it tracks includes: + +- `pipelines` — all discovered pipeline definitions +- `currentPipeline` — the active instance being processed +- `currentPipelineData` — metadata about the active pipeline +- `currentPipelineName` and `currentPipelineIndex` — selection state +- `previousPipeline` — prior pipeline for change events +- `paused` and `pauseReason` — whether processing is temporarily halted +- `latestSnapshot` and `lastInitialSnapshot` — profiling or inspection snapshots +- `pipelineOutputPosters` — objects receiving processed output mats +- `pipelineFpsCounter` — throughput measurement +- `pipelineExceptionTracker` — crash/exception monitoring + +This state is what the GUI uses to show the active pipeline, the app uses to decide whether to continue processing, and the exception system uses to show the right diagnostics. + +## Pipeline discovery and instantiation + +The app supports more than one kind of runtime pipeline source. During startup, `PipelineManager.init()` performs the crucial registration steps: + +1. adds the built-in default pipeline, +2. scans the classpath for additional pipeline classes, +3. registers the common pipeline instantiators, +4. prepares the runtime to swap to an initial pipeline. + +The most notable instantiators are: + +- `DefaultPipelineInstantiator` +- `ProcessorInstantiator` + +These map classes or runtime types to actual objects that can be executed. The patterns in this package allow the manager to support: + +- standard `OpenCvPipeline` implementations, +- FTC-style `VisionProcessor` based implementations, +- and potentially custom pipeline classes introduced by user workspace code. + +This is a major reason the app can mimic FTC development and still feel native to a desktop simulation environment. + +## Initialization flow + +A typical initialization path looks like this: + +- `EOCVSim` creates the runtime and injects `PipelineManager` +- `PipelineManager.init()` runs as part of the orchestrator lifecycle +- the default pipeline is added +- the app scans the classpath for pipeline classes +- instantiators are registered +- the runtime subscribes event handlers for lifecycle and exception behavior +- the active pipeline is selected after startup or build completion + +This is one reason the subsystem is important: it is not just a collection of classes, but a real orchestrated pipeline environment in which the user code is loaded and executed according to app lifecycle rules. + +## The event-driven runtime model + +The pipeline manager uses `EventHandler` heavily instead of relying on direct calls from every class. That keeps the system loosely coupled while still allowing many components to react to pipeline-level state changes. + +Key event handlers include: + +- `onUpdate` — fired when the pipeline loop runs +- `onPipelineChange` — fired when switching to another pipeline +- `onPipelineTimeout` — used when the pipeline exceeds allowed processing time +- `onPause` and `onResume` — user or system driven pause handling +- `onPipelineListRefresh` — used to refresh GUI selection state + +These events are not ornamental. They are part of the runtime’s communication layer. For example, when a pipeline change occurs, the manager resets counters, clears exception output windows, and calls the lifecycle hooks for each attached handler. That means other systems can respond without knowing the details of the pipeline internals. + +## Actual execution flow: from frame to output + +The run loop is more concrete than a generic “process frame” description. In the `PipelineManager.run()` method, the system does the following in order: + +1. It checks whether the pipeline is paused or no pipeline is active. +2. It reads the latest frame from `InputSourceManager.lastMatFromSource`. +3. It records the start of a frame in the shared `PipelineStatisticsCalculator`. +4. It launches a coroutine on a per-pipeline dispatcher (`currentPipelineContext`), which is a dedicated single-thread context named like `Pipeline-MyPipeline`. +5. If the current pipeline has not yet completed its first initialization, it calls `preInit()` on each subscribed `PipelineHandler`. +6. It records a `beforeProcessFrame()` timestamp and calls `currentPipeline.processFrameInternal(inputMat)`. +7. It records `afterProcessFrame()` and posts the result mat to all registered `MatPoster`s. +8. If the pipeline has not yet initialized, it calls `init()` on each handler and sets `hasInitCurrentPipeline = true`. +9. It updates the exception tracker and ends the frame statistics measurement. + +This is a key detail: the actual user `processFrame()` call does not happen synchronously on the main Swing thread. It is executed in a coroutine-backed worker context, and the manager waits only up to a configured timeout. + +The reason this matters is that a buggy pipeline should not freeze the entire simulator UI for an indefinite period. The runtime isolates costly or hung processing in a separate job and then uses cancellation to recover. + +## Timeout and fallback behavior + +The timeout model is one of the most important parts of the runtime. It is configured in `Config`: + +- `pipelineTimeout` — an enum (`LOW`, `MEDIUM`, `HIGH`, `HIGHEST`) +- `pipelineMaxFps` — a separate limiter controlling the maximum pipeline rate + +The timeout value is consumed in `PipelineManager.run()`: + +- default timeout = `configManager.config.pipelineTimeout.ms` +- if the pipeline has not initialized yet, the manager allows a looser limit: `configTimeout * 1.8` + +Then the pipeline job is wrapped in: + +```kotlin +withTimeout(timeout) { + pipelineJob.join() +} +``` + +If the timeout is exceeded, the code runs the following recovery path: + +- `requestForceChangePipeline(0)` switches back to the default pipeline +- `onPipelineTimeout.run()` fires the timeout event +- the app logs a warning such as “User pipeline X took too long to processFrame … falling back to DefaultPipeline.” +- the job is cancelled in `finally` so it cannot post stale output later + +This is not a generic watchdog; it is the main mechanism that keeps the app usable when a user pipeline blocks or enters an infinite loop. The simulator’s philosophy is to keep running, even if the active user pipeline fails, by replacing it with a safe fallback. + +The same pattern is used for `onViewportTapped()`: the app invokes the user callback in a background job and applies a timeout to it so a UI event cannot permanently stall the runtime. + +## Pause semantics and frame gating + +The runtime has explicit pause logic outside of the timeout layer. `PipelineManager` keeps a `paused` flag and a `pauseReason` enum with values: + +- `USER_REQUESTED` +- `IMAGE_ONE_ANALYSIS` +- `NOT_PAUSED` + +When the app is paused, `run()` exits early before calling `processFrameInternal()`. It still updates the exception tracker, but it does not keep processing frames. This is particularly important when the simulator is waiting for the first image analysis or when the user explicitly pauses the pipeline via the UI. + +`pauseOnImages` is another configuration-aware behavior. During pipeline change, if that setting is enabled and the source is an image-based input source, the manager may pause after the first image passes through the pipeline. That makes it easier to inspect a single frame without the runtime continuously advancing through subsequent images. + +## Pipeline switching and state handoff + +Changing the active pipeline is not just a simple assignment. The `forceChangePipeline(...)` flow does a number of important things: + +- captures the current snapshot so values can be restored later, +- instantiates the next pipeline through the appropriate `PipelineInstantiator`, +- creates a fresh telemetry object (`EOCVSimTelemetryImpl`), +- creates a fresh single-thread coroutine context for that pipeline, +- resets `hasInitCurrentPipeline = false`, +- calls `onPipelineChange.run()`, +- and optionally applies a previous snapshot or static snapshot to the new pipeline. + +This is why pipeline switching is relatively smooth in the simulator: it is not only a UI selection but also a runtime handoff in which telemetry, reflection targets, and coroutine execution state are reinitialized. + +## Why the processing model is safe and resilient + +The runtime’s execution pattern is intentionally defensive: + +- a pipeline runs in an isolated coroutine context, +- its output is only posted if the pipeline still matches the active execution state, +- timed jobs are cancelled aggressively, +- exceptions are caught and routed into `PipelineExceptionTracker`, +- and the system falls back to `DefaultPipeline` when a user pipeline hangs or crashes. + +That combination is what makes EOCV-Sim a usable development environment instead of a fragile demo. The simulator behaves like a real runtime that must protect the host app from the unreliability of untrusted user code. + +## Pipeline handlers and wrappers + +The class `PipelineHandler` and its `SpecificPipelineHandler` implementation serve as adapters between the manager and different runtime behaviors. This is the place where a pipeline can be enriched with extra execution logic without bleeding that logic into the central manager itself. + +This allows patterns such as: + +- telemetry injection, +- pipeline output forwarding, +- timing observation, +- custom exceptions or output logs, +- user hook integrations. + +The architecture is intentionally layered: the manager is the orchestration layer, the handlers are the behavior adapters, and the actual user pipeline object is the execution logic. + +## Output posting and viewport rendering + +The pipeline runtime does not render graphics directly; it posts the output `Mat` to registered poster objects. `pipelineOutputPosters` is a list of `MatPoster`s, and the viewport object is one of them. + +This is important because it decouples the pipeline execution from the actual visual front end. The pipeline can produce a frame and push it into the output chain without needing to know whether the output is going to a Swing component, a file, or another debugging pipeline stage. + +The render path is roughly: + +- pipeline returns a processed `Mat` +- manager posts output to visualizer viewport +- viewport creates/copies the data for rendering +- the renderer draws the output canvas +- user hook methods (like `onDrawFrame`) may annotate the frame + +## Telemetry and FTC compatibility + +The app has a strong FTC compatibility story. It includes its own telemetry implementation (`EOCVSimTelemetryImpl`) and wrappers around FTC runtime concepts. This is not just a convenience layer; it is a core compatibility feature. + +Pipeline user code often expects: + +- a `Telemetry` object, +- status messages, +- error items, +- `addData`-style updates, +- and FTC-like lifecycle semantics. + +The simulator counteracts this by integrating telemetry into the pipeline runtime. The manager tracks `currentTelemetry` and updates it with runtime status, warnings, and error messages. That gives user code a familiar environment even though it is actually running on a desktop JVM. + +## Exception handling and crash containment + +A pipeline is user-supplied logic, and user logic can fail. `PipelineExceptionTracker` is therefore a critical piece of the pipeline subsystem. + +The tracker is hooked into the runtime and reacts to exceptions by: + +- recording the event, +- notifying the GUI if needed, +- updating telemetry, +- clearing the exception state when recovered, +- and surfacing the issue in a user-friendly output window. + +This behavior matters because the app is designed to be a development tool. It should fail gracefully when a pipeline throws, rather than crashing the whole application because one custom class misbehaved. + +## Compiled pipeline flow and live rebuilds + +The workspace-driven compile flow is probably the most distinctive pipeline feature in the project. It is handled by `CompiledPipelineManager` and related classes under `pipeline/compiled`. + +This subsystem is responsible for: + +- preparing the compile output directories, +- respecting workspace configuration, +- compiling Java source files from the workspace, +- writing a generated pipeline JAR, +- loading the resulting classes with `PipelineClassLoader`, +- and registering them so the user can switch to the newly built pipeline. + +The compile process is intentionally asynchronous. It does not freeze the UI while user code compiles, and it disables the compile button or menu action while a build is running. + +### Compiler details + +The core file `PipelineCompiler.kt` is responsible for compiling user workspace files into a JAR. It uses a custom file manager and class path handling to build Java classes in a controlled environment. Once the build is successful, `CompiledPipelineManager.loadFromPipelinesJar()` loads the classes from the jar and asks `PipelineManager` to add them to the runtime. + +This is one of the defining features of the simulator: user code in a workspace can be changed and then recompiled and reloaded without restarting the application. + +## Snapshot and reflective tuning support + +The app also supports runtime introspection of pipeline state via `PipelineSnapshot` and virtual reflection utilities. This is used when the simulator wants to show live field values or let users tune them without recompiling the whole project. + +This is highly relevant to the “variable tuner” feature in the GUI. The underlying mechanism allows the app to: + +- see fields in the current pipeline, +- determine if they are tunable, +- capture values in a snapshot, +- and optionally restore or update them at runtime. + +That is the reason the project can support interactive tuning while a pipeline is actively processing frames. + +## Runtime execution loop + +The rough runtime loop is: + +1. source produces a `Mat` +2. `PipelineManager` receives the frame through the update cycle +3. the active pipeline processes it +4. exceptions are monitored at every step +5. output is forwarded to the viewport +6. the main loop updates telemetry and stats +7. the renderer paints the result and overlays timing information + +This simple loop is repeated continuously during the app’s runtime and is the reason the simulator feels dynamic and responsive. + +## Relationship with other subsystems + +The pipeline runtime has strong coupling to multiple other subsystems: + +- `InputSourceManager` provides the frame source +- `WorkspaceManager` provides source code and rebuild triggers +- `Visualizer` displays the output and controls the viewport +- `ConfigManager` supplies runtime settings like FPS and pause behavior +- `PluginManager` can add or alter capabilities and UI hooks +- `TunerManager` uses reflection and snapshotting to expose tunable fields + +This is an example of a healthy layered architecture: each subsystem owns a coherent concern, but they are all connected through runtime events and lifecycle orchestration. + +## Why this subsystem matters + +This is the core of the app. If the pipeline runtime is strong, the simulator is useful. If it is brittle, the whole experience feels broken even if the GUI is polished. + +The simulator’s value comes from this subsystem being able to: + +- run user pipeline code, +- mimic FTC semantics, +- compile workspace sources live, +- show errors without killing the app, +- and present processed frames in real time. + +That is what makes the app more than a simple viewer: it is a working pipeline development environment. diff --git a/documents/06-input-sources.md b/documents/06-input-sources.md new file mode 100644 index 00000000..1cd8a2a2 --- /dev/null +++ b/documents/06-input-sources.md @@ -0,0 +1,108 @@ +# Input sources subsystem + +## Purpose + +The input source subsystem is the source-of-truth for media flowing into the simulator. It decides which input stream is active, loads it safely, and converts it into the OpenCV `Mat` format expected by pipelines. + +The main runtime classes are: + +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceManager.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSource.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceInitializer.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceLoader.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/input/source/` + +## High-level role in the app + +The subsystem sits directly between the environment and the processing pipeline: + +- input sources produce frames or images, +- the pipeline runtime consumes them, +- the viewport displays the processed result. + +The producer/consumer chain is therefore: + +source → `InputSourceManager` → pipeline runtime → viewport + +## `InputSourceManager`: runtime source controller + +`InputSourceManager` is the main controller for the whole source layer. It keeps track of: + +- the currently active source (`currentInputSource`) +- the most recently acquired frame (`lastMatFromSource`) +- the full set of available sources (`sources`) +- the default source fallbacks +- per-source initialization and failure handling +- source selection and deletion logic + +The manager also owns a `MatRecycler` buffer pool. This is a deliberate optimization: instead of repeatedly allocating new native OpenCV matrices for each frame, the runtime reuses buffers for performance and lower churn. + +## Source types supported by the app + +The codebase includes multiple concrete source implementations under `input/source/`: + +- `ImageSource` — loads image files and returns them as frames +- `VideoSource` — reads video streams or files +- `CameraSource` — interacts with a webcam or camera device +- `HttpSource` — streams from an HTTP endpoint +- `NullSource` — an empty placeholder used when there is no actual source + +This design matters because the simulator needs to support a broad range of realistic inputs without coupling the pipeline runtime to a single external medium. + +## Default startup sources + +At startup, the app creates a few default packaged image sources. These are bundled demo assets, such as sample Ultimate Goal images, which let the simulator show meaningful output right away before the user adds their own content. + +If no valid source exists, it falls back to a `NullSource` to avoid a crash and keep the app usable. + +## Initialization and timeout logic + +A source is not simply “used” once it is selected. `InputSourceInitializer` handles initialization tasks such as: + +- opening the source, +- waiting for a successful state, +- applying timeouts, +- canceling slow initialization, +- logging and signaling failures. + +This is needed because sources may depend on hardware, disks, or network endpoints that are not always immediately ready. The manager surfaces failures by raising `onInputSourceInitError` and can fall back to a previous source or default source if needed. + +## Frame acquisition and conversion + +During runtime, the manager repeatedly pulls frames from `currentInputSource` and converts them into the RGBA (`CV_8UC4`) format expected by the viewport renderer. + +The conversion path effectively does: + +- request `update()` from the source, +- check that a valid non-empty `Mat` was produced, +- convert from RGB to RGBA using OpenCV color conversion, +- recycle the old `Mat` buffer in the recycler, +- place the new frame in `lastMatFromSource`. + +This is one of the core low-level runtime steps that makes the rest of the simulator work. + +## Pause behavior for image sources + +The config setting `pauseOnImages` is used here. When enabled, and the selected source is an image, the app can pause the pipeline after the frame is loaded in order to analyze that image once rather than continuously processing a static image with no new frames. + +This is especially useful for debugging still-image pipelines, where the user wants single-frame analysis and a stable equation rather than constant reprocessing. + +## Loading and persistence of user-created sources + +`InputSourceLoader` stores user-created sources to disk, which allows the app to restore the same set of input sources on next launch. This is important because users often create custom image, camera, or URL-based sources and expect them to remain available across sessions. + +This gives the app a “project-like” concept of input configuration, not just ephemeral runtime state. + +## Relationship to the pipeline runtime + +The input system and pipeline runtime are intentionally decoupled: + +- the input manager knows how to fetch frames, +- the pipeline manager knows how to execute logic on a given frame, +- the rendering layer knows how to display the output. + +This separation makes the app more modular and easier to reason about. A user can change the input source without rewriting the pipeline code, or revisit the pipeline logic without altering how frames are acquired. + +## Why this subsystem matters + +The input source system is one of the app’s foundational runtime layers. Without it, the simulator has no data to send to the pipeline, and the visualizer would be empty. It also supports the app’s “desktop development” story by letting users load real image samples, local video, or live camera-based sources for experimentation and debugging. diff --git a/documents/07-workspaces.md b/documents/07-workspaces.md new file mode 100644 index 00000000..3a5ff6dd --- /dev/null +++ b/documents/07-workspaces.md @@ -0,0 +1,90 @@ +# Workspaces subsystem + +## Purpose + +The workspace subsystem is the developer-facing part of the simulator. It allows users to work in a project-like folder structure where source files and resources live separately from the app code itself, then get recompiled and reloaded at runtime. + +The main code lives in: + +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/WorkspaceManager.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/config/` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/workspace/util/` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/pipeline/compiled/CompiledPipelineManager.kt` + +## What a workspace is + +A workspace is a directory that contains the project files the app uses to build runtime pipelines. It is not just a random folder; it is a structured source tree that includes: + +- source files under a `src` path, +- resources under a separate resources folder, +- excluded directories and file rules, +- configuration metadata for the workspace, +- and information the compiler uses to build classes. + +The workspace manager tracks each of these elements and provides accessors for both the source tree and the resource tree. + +## `WorkspaceManager`: the central coordinator + +`WorkspaceManager` is the main class in this subsystem. It does the following: + +- tracks the active `workspaceFile` +- loads or creates the workspace config +- keeps source and resource paths in sync with the config +- discovers Java source files and resource files +- sets up file watching for real-time updates +- triggers rebuilds when files change +- creates workspaces from templates for new projects + +The class is also tightly integrated with the pipeline runtime. It uses the `CompiledPipelineManager` to trigger builds whenever the workspace changes. + +## Workspace configuration model + +The workspace config is stored and managed by the classes in `workspace/config/`. It contains metadata such as: + +- source folder path, +- resources folder path, +- excluded relative paths, +- excluded file extensions, +- version metadata used to maintain compatibility. + +The manager automatically saves the config when it changes and recreates it if the existing config cannot be parsed or is missing. + +The important point is that this is not ad hoc project state; it is part of the app’s runtime model, and the compiler builds against it as a real workspace definition. + +## File watching and live updates + +One of the most important features of the workspace subsystem is automatic file watch behavior. `WorkspaceManager` sets up a `FileWatcher` so changes in source/resource folders can trigger rebuilds. + +The workflow is: + +1. workspace files change, +2. the file watcher notices, +3. `CompiledPipelineManager.asyncBuild()` is called, +4. the user code is compiled into runtime classes, +5. the pipeline manager reloads/updates the available pipeline list. + +This makes the app feel much more like a live development environment than a static code runner. It is a core part of why the simulator is useful for iterative pipeline development. + +## Compiler integration + +The workspace is tightly tied to the pipeline compiler. `CompiledPipelineManager` is the bridge between the file system and the running app. It knows where the default workspace lives, creates compiler output folders, and compiles workspace Java sources into a JAR that is then loaded using a custom class loader. + +This means users can edit files in the workspace and then immediately see the simulator detect and load their updated pipeline classes without restarting the whole app. + +## Default workspace behavior + +The app includes a default workspace and will recreate or update it if the version metadata differs. This makes the simulator self-contained and provides beginners with a ready-to-use starting point. + +The default workspace is not just a demonstration; it is the project model the app expects if the user does not choose a custom workspace. + +## Template support + +The workspace system also includes template support (`WorkspaceTemplate`, `DefaultWorkspaceTemplate`, `GradleWorkspaceTemplate`). This allows the app to create new workspace folders with appropriate scaffolding and default contents rather than forcing the user to set up everything manually. + +This is the app’s way of smoothing the on-ramp for new developers. + +## Why this subsystem matters + +Without workspaces, the app would be limited to bundled code and impossible to extend dynamically. The workspace subsystem gives the simulator its “code in a project folder, compile and reload live” behavior. That is arguably one of the project’s biggest differentiators from a simple OpenCV viewer or demo tool. + +It is the layer that ties the app together as a true development environment. diff --git a/documents/08-plugins-and-superaccess.md b/documents/08-plugins-and-superaccess.md new file mode 100644 index 00000000..edb92478 --- /dev/null +++ b/documents/08-plugins-and-superaccess.md @@ -0,0 +1,187 @@ +# Plugins and SuperAccess subsystem + +## Purpose and scope + +The plugin subsystem is the simulator’s extension mechanism. It allows external JARs and built-in modules to add runtime features without requiring a full application rebuild. In a project like EOCV-Sim, that matters because custom vision tools, extra GUI elements, and specialized integrations are often more practical as plugins than as permanent hard-coded app features. + +The main implementation is spread across a few packages: + +- `../VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginManager.kt` +- `../VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/FilePluginLoaderImpl.kt` +- `../VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/EmbeddedPluginLoader.kt` +- `../VisionBench/src/main/java/org/deltacv/eocvsim/plugin/loader/PluginClassLoader.kt` +- `../VisionBench/src/main/java/org/deltacv/eocvsim/plugin/repository/PluginRepositoryManager.kt` +- `../VisionBench/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemon.kt` +- `../VisionBench/src/main/java/org/deltacv/eocvsim/plugin/security/superaccess/SuperAccessDaemonClient.kt` +- `../VisionBench/src/main/java/com/github/serivesmejia/eocvsim/plugin/api/impl/` + +This subsystem is responsible for: + +- finding plugin files, +- loading plugin metadata, +- resolving repo-managed plugins, +- enabling/disabling plugins, +- exposing a controlled API to plugins, +- and enforcing privilege approval for anything sensitive. + +## Why a plugin subsystem exists at all + +The app is built as a runtime platform. It has a config system, user workspace, pipeline engine, and GUI, but it also needs a way to add optional extensions without polluting the main app code and without forcing a rebuild for every feature. + +That is why the plugin architecture exists. + +The project does not expose raw internals freely. Instead, plugins interact via a stable API layer, which is why the API classes under `plugin/api/impl` are important: they provide the plugin contract and keep the rest of the app from being directly manipulated by arbitrary third-party code. + +## `PluginManager`: the plugin lifecycle controller + +`PluginManager` is the main manager for all plugin lifecycle behavior. It is effectively the top-level coordinator for the subsystem. + +In `init()`, it does a sequence of setup tasks: + +1. attaches a plugin output handler to the app’s UI lifecycle, +2. initializes repository support, +3. scans the plugin folder and any resolved repo plugin files, +4. creates file-based loaders for each plugin JAR, +5. loads the plugin metadata from each plugin definition, +6. checks duplicates and embedded plugins, +7. calls `loadPlugins()` to bring the plugins into the runtime, +8. enables them after the rest of the app is ready. + +The manager also tracks: + +- plugin files found in the repo or plugin folder, +- plugin loaders that have been created, +- plugin source type (`FILE`, `REPOSITORY`, `EMBEDDED`), +- loaded plugin hashes to detect duplicates, +- and output messages shown to the user while the plugin system is active. + +This makes the plugin system more than a thin jar loader. It is a runtime management layer. + +## Plugin sources and loader model + +The app distinguishes among plugin sources: + +- `FILE` plugins — JARs located in the plugin folder +- `REPOSITORY` plugins — resolved from repository metadata +- `EMBEDDED` plugins — plugins that ship with the app itself + +This classification matters for both user experience and security. A repository-managed plugin may be checked for updates; a file plugin may be user-managed; an embedded plugin is trusted as part of the app distribution. + +### `FilePluginLoaderImpl` + +This loader handles normal plugin JAR files. It resolves plugin info from the plugin artifact and registers the plugin with the runtime loader system. + +### `EmbeddedPluginLoader` + +This is used for built-in plugins that are packaged with the application. It allows the app to include optional features without forcing them to be installed manually. + +### `PluginClassLoader` + +A plugin class loader is necessary because plugins are external code and should not be loaded in the same classpath as the base app. This provides isolation and prevents plugin code from accidentally clashing with app classes or each other. + +This is one of the most important engineering decisions in the subsystem: plugin code is treated as a separate runtime unit. + +## Repository resolution and dependency management + +The repository layer is handled by `PluginRepositoryManager`. This class reads a repository TOML file, configures a Maven resolver, and resolves plugin artifacts from remote repositories. + +The key responsibilities include: + +- reading repository configuration from `repository.toml`, +- registering remote repositories with the Maven resolver, +- resolving plugin artifacts and transitive dependencies, +- caching plugin results locally, +- checking whether a plugin is outdated, +- prompting the user to update and restart when a newer plugin version exists. + +This repository mechanism is more sophisticated than simply copying JARs into a folder. It tries to manage plugin versions and dependency resolution in a more controlled manner. + +### Cache behavior + +`PluginRepositoryManager` stores dependency information in a cache file and checks whether transitive dependencies are still valid. This reduces repeated downloads and ensures that plugins are not accidentally loaded with stale or partially missing dependency sets. + +### Update prompts + +The manager can show a Swing dialog to prompt the user to update a plugin. It will surface the latest resolved version and ask whether the user wants to update and restart the app. This is important because plugin update behavior is a runtime-affecting decision and not something the app should silently do behind the user’s back. + +## Plugin API surface + +The app does not expose the entire application runtime to every plugin. Instead, plugins interact through a controlled API set. Some of the key api implementations are: + +- `EOCVSimApiImpl` +- `VisualizerApiImpl` +- `PipelineManagerApiImpl` +- `InputSourceApisImpl` +- `EventHandlerHookApiImpl` +- `DialogFactoryApiImpl` +- `ConfigApiImpl` + +This is the plugin contract. It allows plugin code to talk to the simulator in a stable manner without taking over the entire application. The benefit is cleaner separation of concerns: plugins work with explicit APIs instead of direct references to app internals. + +## Security design and SuperAccess + +This project treats plugins as potentially untrusted code. The system’s response is not “load everything unconditionally,” but rather “restrict by default and ask for permission when more power is needed.” + +The key security mechanism is `SuperAccess`. + +### `SuperAccessDaemon` + +This is a separate JVM process that handles security-sensitive requests from plugins. It listens on a websocket connection and mediates plugin access checks. It stores granted access in a local file and validates whether a plugin is already allowed before asking the user again. + +The daemon handles two kinds of security events: + +- `Request` — a plugin asks for elevated privileges or access +- `Check` — the client asks whether a given plugin already has granted access + +This is a system-level approval flow, not just a UI checkbox. The actual trust decision is made outside the main app process. + +### `SuperAccessDaemonClient` + +The client side of the daemon is the runtime component that connects to the daemon and sends grant/check requests. It is the bridge between the main app and the privileged background process. + +### `SuperAccessRequest` + +When a plugin requests elevated access, the app shows a dialog asking the user to approve or deny the request. The dialog includes contextual warnings and security messaging, so the user is aware that the plugin is asking for broad privileges. + +This is a critical UI workflow because it makes the trust boundary explicit. + +## Authority and trust validation + +The code also includes authority-fetching and signature validation logic. The daemon can inspect the plugin’s declared author and verify whether a trusted authority matches the plugin signature. That means the app can distinguish between: + +- a plugin signed by a trusted authority, +- a plugin claiming to be from a given author but not actually signed, +- and a plugin with no trustworthy provenance. + +This is a major part of the security story and a significant difference between a toy plugin loader and a real extension platform. + +## Why the trust model is so important + +EOCV-Sim runs user-provided code. That is not a trivial risk model. Even though plugin authors are likely well-intentioned, they are still executing code in the same Java process as the application. If the app silently allows broad access, the extension mechanism becomes a vector for data loss or system compromise. + +The project’s response is to keep the default trust model restricted and to require explicit user approval for anything beyond the sandboxed access of a normal plugin. This is exactly what a robust plugin system should do. + +## Plugin output and runtime feedback + +The plugin system also has a user-facing output channel through `PluginOutputHandler`. This is important because plugins often need logs, update messages, failure diagnostics, or permission warnings. Without a dedicated output surface, plugin behavior would be opaque and difficult to debug. + +The design is to provide plugin output as part of the same application UX rather than as an invisible side effect. That makes plugin lifecycle events visible to the user and reduces confusion. + +## Relationship to the app runtime + +The plugin subsystem does not sit in isolation. It integrates with the rest of the application at several points: + +- it attaches to startup and lifecycle events, +- it can use the visualizer API, +- it can interact with config values, +- it can react to pipeline and source events, +- it can show dialogs and user notifications, +- it can reconnect after restart when a repo-managed plugin updates. + +This means the plugin layer is not a separable side feature. It is woven into the app’s runtime model and tooling experience. + +## Why this subsystem matters + +The plugin system is one of the most advanced parts of the app because it is both a developer extension mechanism and a security-sensitive runtime boundary. It allows optional features to be added without cluttering core code, while also preventing the app from turning into an unrestricted execution environment. + +That balance is exactly what makes the subsystem valuable: it gives the project extensibility and safety at the same time. diff --git a/documents/09-vision-and-common-libraries.md b/documents/09-vision-and-common-libraries.md new file mode 100644 index 00000000..54119a4f --- /dev/null +++ b/documents/09-vision-and-common-libraries.md @@ -0,0 +1,209 @@ +# Vision and Common libraries + +## Purpose of the shared layers + +The `Common` and `Vision` modules are the underlying infrastructure that gives the app its modularity and runtime flexibility. Together, they separate the high-level application logic from the lower-level concerns of lifecycle coordination, image rendering, and OpenCV integration. + +The subprojects are important because they let the app be built as a layered system rather than a single giant package with all behaviors tied together. + +## `Common` module: shared foundation + +The Common module contains the reusable infrastructure that most of the app relies on. It includes things like: + +- orchestration abstractions (`Orchestrator`, `Orchestrable`, `PhaseOrchestrableBase`) +- logging helpers and concurrency utilities +- serialization support +- pipeline statistics and utility logic +- shared file and environment helpers +- other general-runtime constructs that are not app-specific + +This module is the “hidden backbone” of the architecture. It provides the behavior that keeps the app consistent without duplicating code across subsystems. + +### Lifecycle abstraction in Common + +The `Orchestrator` pattern is one of the most important parts of the Common layer. It gives the app a standard way to initialize and destroy major subsystems, which is essential when a system has several dependencies and must be assembled in order. + +The Common module is therefore where the app’s runtime lifecycle model is defined, even though the actual application logic lives in the main module. + +### Utility and general-purpose behavior + +The Common layer also includes general-purpose support for logging, serialization, metadata, and other operational functions that are not directly tied to GUI or pipeline logic. In a large Java/Kotlin project, this shared layer is what prevents repeated wiring and repeated helper code. + +For a deeper look at the runtime infrastructure itself, see [10-runtime-utilities.md](./10-runtime-utilities.md). That companion guide focuses on the most important cross-cutting abstractions: the event system, lifecycle orchestration, and utility classes that support startup and runtime coordination. + +## `Vision` module: rendering and display adaptation + +The Vision module is the part of the project that bridges OpenCV and the Swing desktop app. It is where the simulator translates the live Mat pipeline output into something the user can see and interpret visually. + +In practice, the module is bigger than a simple Swing helper. It includes the compatibility layer that lets EOCV-Sim mimic FTC camera APIs, a desktop viewport layer for rendering frames, and a source abstraction for webcam or image-backed inputs. The result is a system that feels like a real FTC camera pipeline but runs on a desktop JVM. + +Important classes include: + +- `SwingOpenCvViewport.kt` — desktop Swing + Skia viewport implementation +- `OpenCvViewRenderer.java` — actual canvas drawing and overlay logic +- `SkiaPanel.kt` — Swing host surface used by the render layer +- `OpenCvViewport.java` — FTC/OpenCV viewport contract +- `VisionSource.java` / `VisionSourceBase.java` — abstraction for incoming image sources +- `FrameReceiverOpenCvCamera.java` — bridge between a source and FTC camera semantics +- `VisionPortalImpl.java` — compatibility shim for FTC `VisionPortal` usage +- `VisionProcessor.java` and related FTC wrappers — processor APIs simulated in the desktop runtime + +### The bigger scope of the `Vision` module + +The `Vision` module is not just “browser-like display code.” It is effectively the app’s compatibility and rendering backbone. It has three distinct responsibilities: + +1. display and paint an image stream to a Swing-based viewport, +2. emulate FTC/OpenCV camera and processor abstractions so user code can be written in a familiar API, +3. bridge external input sources (webcams, files, camera-like streams) into the OpenCV pipeline model. + +This is why the module is central to the project’s goal: it lets a user pipeline written against FTC-style APIs run in a desktop environment without needing a robot or Android runtime. + +### `OpenCvViewport` and the render contract + +The `OpenCvViewport` interface is the low-level contract used by the runtime to render and display frames. It defines operations such as: + +- `post(Mat frame, Object userContext)` — enqueue a processed frame for display +- `setFpsMeterEnabled(boolean)` — enable/disable the stats overlay +- `pause()` / `resume()` / `activate()` / `deactivate()` — control viewport state +- `notifyStatistics(float fps, int pipelineMs, int overheadMs)` — send render analytics +- `setRenderHook(RenderHook)` — allow user drawings or annotations to be added + +The render hook is important because it allows a pipeline’s `onDrawFrame(...)` contract to be mirrored in the desktop app. The user can draw overlays on top of the image, and those hooks are executed in the same conceptual place as they would be on-device. + +This means the viewport layer is not purely a display widget. It is part of the same API contract that the pipeline runtime expects from FTC/OpenCV cameras. + +### `OpenCvViewRenderer`: scaling, overlays, and frame composition + +`OpenCvViewRenderer` is where most of the visual drawing logic sits. It has to do a number of tricky things correctly: + +- keep the image centered and scaled to fit an arbitrary viewport size, +- preserve the source aspect ratio, +- draw a black background so transparent or semi-transparent OpenCV output does not produce artifacts, +- convert `Mat` to a `Bitmap` for Android/Skia compatibility, +- apply rotation policies when the image should be optimized for view orientation, +- and draw the FPS / timing overlay when enabled. + +The `unifiedDraw()` method is the main rendering pass. It calculates the scaled destination rectangle, draws the bitmap in the correct location, calls any user `RenderHook`, and then overlays the stats box. This is the direct visual equivalent of the FTC camera monitor view: a real image, with optional overlays and diagnostics. + +The FPS meter itself is intentionally part of the rendering layer, not the app config layer. Its content is produced from statistics already gathered by the pipeline runtime, then drawn on the canvas by the renderer. That places the logic at the correct layer and keeps it independent from the settings system. + +### `SwingOpenCvViewport`: the desktop assembly layer + +`SwingOpenCvViewport` is the concrete implementation that actually plugs into the Swing UI. It does several things at once: + +- creates and owns a `SkiaLayer` for rendering within Swing, +- holds a frame queue for live preview images, +- uses a `MatRecycler` to avoid repeated allocations during hot render loops, +- tracks active/paused/stopped viewport state, +- posts output mats to downstream posters or screenshot-like output consumers, +- and reuses a last frame when the viewport is paused. + +The queue is important. A live preview path should never block the whole app on a big render event. Instead, the viewport keeps a small `EvictingBlockingQueue` of recent frames and chooses the most relevant frame for the next paint cycle. It also returns recycled mats to a buffer so native memory is reused rather than repeatedly allocated. + +This is a very desktop-native implementation of the same general idea found in Android camera preview rendering: accept frames from the pipeline, store or queue them, and draw them to the user-facing surface with minimal latency. + +### Source abstraction: `VisionSource`, `VisionSourceBase`, and `FrameReceiver` + +The desktop motion picture side of the Vision module is not just a viewport. It also exposes a generalized camera-source abstraction for image acquisition. + +The key pieces are: + +- `VisionSource` — a source that can start, stop, attach receivers, and provide a frame stream +- `VisionSourceBase` — a reusable worker-thread implementation that polls frames and distributes them to attached consumers +- `FrameReceiver` — a consumer contract for a frame stream + +This is the part of the code that decouples “where the image comes from” from “how it is rendered.” A source can be backed by a real webcam, a recorded stream, or some other capture mechanism; the rest of the system only cares that it emits `Mat` frames with timestamps and can be attached to a consumer. + +`VisionSourceBase` runs a helper thread that repeatedly calls `pullFrame()`, then pushes each frame to any attached `FrameReceiver`s. This architecture allows the app to treat camera-like data as a generic feed rather than tying the rest of the code to a specific hardware implementation. + +### Camera compatibility: `FrameReceiverOpenCvCamera` + +`FrameReceiverOpenCvCamera` is one of the most revealing classes in the module. It acts as a compatibility shim between the abstracted input source and the FTC/OpenCV camera model. + +It extends `OpenCvCameraBase` and implements `OpenCvWebcam` and `FrameReceiver`, which means it can behave like a real FTC webcam in the rest of the codebase while actually receiving frames from a `VisionSource` abstraction. The class does things like: + +- open/close the camera device, +- start and stop streaming, +- request image sizes and rotations, +- route camera controls to a `CameraControlMap`, +- call `handleFrameUserCrashable(frame, timestamp)` when a new frame arrives. + +This class is critical because it lets EOCV-Sim mimic the same camera lifecycle expected by user code written for FTC. The app is therefore not merely drawing a frozen image; it is reconstructing the expected camera runtime semantics around a desktop input source. + +### `VisionPortal` compatibility layer + +`VisionPortalImpl` is another important compatibility layer. It recreates the FTC `VisionPortal` lifecycle for processor-based pipelines: + +- it creates the underlying camera, +- opens it asynchronously, +- starts the stream at a chosen resolution, +- assigns a `ProcessingPipeline`, +- initializes each attached `VisionProcessor`, +- and updates the enabled/disabled processor state. + +The pipeline created here is a `TimestampedOpenCvPipeline`, which is a variant of the standard pipeline that carries capture timestamps. This matches FTC’s real-time processing model more closely than a plain `OpenCvPipeline` and is part of the reason these pipelines feel familiar even when they run on a desktop app. + +This is a major part of the Vision module’s hidden work: it is not just presenting images, but preserving the FTC API surface so user code is minimally disrupted when moved from robot hardware to the simulator. + +### `VisionProcessor` ecosystem and AprilTag support + +The module also contains FTC-compatible processor implementations such as: + +- `VisionProcessor.java` +- `ColorBlobLocatorProcessor*` +- `PredominantColorProcessor*` +- AprilTag-related classes under `org.firstinspires.ftc.vision.apriltag` + +These provide the expected FTC-style processing objects used by real robotics vision work. The app does not need to reimplement every algorithm in full to be useful; instead, it provides the API surface and compatibility layer so that a vision pipeline can run and be tested against sample input. + +This is a good example of how the project intentionally reproduces the platform model rather than trying to invent a completely separate pipeline abstraction. The goal is to make the simulator feel “real” to FTC developers. + +### `SkiaPanel` and Swing integration + +`SkiaPanel.kt` is the Swing host that allows the viewport to draw through the Skia rendering stack. It sits between Swing/JComponent and the native rendering logic and is responsible for binding the renderer to a GUI component. This keeps the preview surface in the Swing thread model while still using Skia for actual canvas drawing. + +The result is a hybrid architecture: + +- Swing handles the desktop layout and component lifecycle, +- Skia handles rendering, +- OpenCV handles the image data, +- and the FTC compatibility layer preserves the expected programming model. + +### Why this layer is more than a UI wrapper + +The Vision module is important because it is the place where EOCV-Sim solves the hardest compatibility problem: how to run FTC-oriented vision code on a desktop app without changing the user-facing API. + +That is why the project can offer: + +- a live desktop preview, +- camera-like lifecycle semantics, +- processor and pipeline compatibility, +- rotation/rendering policies, +- and output hooks that behave like a real OpenCV viewport. + +The layer is therefore not a cosmetic visualizer. It is one of the central runtime abstractions that makes the simulator credible as a development tool. + +## Relationship between the layers + +The separation is intentional: + +- `Common` = shared operational infrastructure +- `Vision` = display and OpenCV adaptation layer +- `VisionBench` = app-level runtime, config, GUI, workspace, and pipeline orchestration + +This arrangement keeps the code easier to maintain and lets each subsystem specialize in what it does best. + +## Why this split is valuable + +This multi-module model is important because it keeps the application from becoming a single giant runtime blob. + +It enables the project to support: + +- app-level orchestration without mixing in rendering code, +- OpenCV viewport logic without embedding it inside the desktop GUI, +- shared utilities without duplicating logic across the app, +- and a cleaner path to future extensions or alternate visual backends. + +## Summary + +The `Common` and `Vision` modules are the reusable foundation of the simulator. They provide the runtime scaffolding and rendering layer that make the higher-level desktop app possible. Without these layers, the rest of the codebase would be much harder to maintain and considerably less modular. diff --git a/documents/10-runtime-utilities.md b/documents/10-runtime-utilities.md new file mode 100644 index 00000000..b427917d --- /dev/null +++ b/documents/10-runtime-utilities.md @@ -0,0 +1,110 @@ +# Runtime utilities and infrastructure + +The codebase has a few foundational utility systems that are easy to overlook because they are not tied to a single screen or a single subsystem. These utilities quietly power lifecycle management, listener-driven notifications, and runtime scanning. They are some of the most important pieces to understand when working on the simulator beyond the GUI and pipeline code. + +## Event handling: `EventHandler` and `ParamEventHandler` + +The shared event system is the app’s main way to react to runtime signals without maintaining direct references between unrelated subsystems. This prevents a large number of managers from tightly coupling to each other. + +The base abstraction is `ParamEventHandler`, which supports a typed payload and has a general listener lifecycle: + +- `attachPayload(listener)` registers a persistent listener +- `oncePayload(listener)` registers a listener that fires once +- `run(payload)` dispatches the event to all listeners +- `removeListener(id)` removes a specific listener +- `removeAllListeners()` clears the registry + +The implementation is intentionally concurrency-aware. It keeps separate queues for persistent and one-shot listeners and defers listener registration/removal while dispatch is in progress. That matters because listeners may add or remove other listeners as an event is firing, and the system needs to avoid a concurrent modification or a mid-dispatch mutation problem. + +The legacy zero-argument API is still exposed as `EventHandler` for compatibility. It behaves like `ParamEventHandler` and keeps the older syntax: + +- `attach { ... }` +- `once { ... }` +- `listener.removeListener()` via the listener context +- `invoke(...)` operator overload + +The `EventListenerContext` is the principal way a listener can self-remove. It gives the callback a handle to the owning `EventHandler` and its `EventListenerId`, so a listener can decide to unregister itself when a condition is met. + +`callRightAway` controls a useful edge feature: a listener may be invoked immediately after registration, either inline or in a provided coroutine scope. That is helpful for integration points that want an event to trigger once right away instead of waiting a full tick. + +Typical uses in the app include: + +- pipeline change notifications +- workspace rebuild events +- plugin output and status signals +- UI refresh hooks +- lifecycle-driven update callbacks + +In short, this system is the app’s “localized pub-sub layer”: the producer emits an event, and any interested subsystem reacts without the producers needing to know the consumers by name. + +## Lifecycle orchestration: `Orchestrator`, `Orchestrable`, and `PhaseOrchestrableBase` + +The app’s startup and shutdown flow is coordinated by the orchestration system in `Common`. The core idea is simple: major subsystems expose lifecycle hooks and dependencies, and the orchestrator executes them in the correct order. + +### Core types + +- `Orchestrable`: a minimal interface with `wire(orchestrator)` +- `PhaseOrchestrable`: adds `init()`, `run()`, and `destroy()` hooks +- `PhaseOrchestrableBase`: convenience base class that holds a `PhaseDependencies` registry +- `Orchestrator`: executes phased tasks in dependency order + +### Phase model + +The orchestrator supports three lifecycle phases: + +- `INIT` +- `RUN` +- `DESTROY` + +Each target may register a callback for one or more phases and declare dependencies for that phase. Dependencies are resolved before a target executes, which makes startup ordering deterministic and helps avoid race conditions during app initialization. + +A subsystem can declare: + +- that it depends on another manager during initialization +- that it can only run once its dependencies are active during runtime +- that it must tear down after other systems finish their teardown + +This is exactly the pattern used by the main app to ensure that config, GUI, input sources, workspace, and plugin systems are created in a safe sequence. + +### Dependency DSL + +The API exposes a small DSL for declaring dependencies. Common patterns look like this: + +- `phase(Orchestrator.Phase.INIT) { target { init() } }` +- `dependsOn(ConfigManager::class)` +- `dependsOn(workspaceManager)` +- `dependency(PluginManager::class, Orchestrator.Phase.RUN)` + +The orchestrator then builds an execution graph for the phase and resolves it in waves. If a dependency cycle exists, it fails early with a clear dependency error instead of silently continuing into an invalid runtime state. + +### Why this matters + +This is one of the biggest architecture decisions in the project. Instead of manually calling initialization code in a giant startup method, the app registers subsystems with explicit lifecycle contracts. That provides several benefits: + +- predictable startup ordering +- less brittle runtime wiring +- cleaner teardown behavior +- easier extension of managers without touching global bootstrap logic + +For example, the visualizer, input source manager, plugin manager, workspace manager, and pipeline manager are all registered as lifecycle-aware components, which lets the runtime treat them as a coherent system rather than a set of loosely related objects. + +## Other major utilities that deserve dedicated documentation + +A few additional utilities are important enough to merit their own guides in the future: + +- `ClasspathScan` — scans the classpath for pipeline classes and plugin bundles using ClassGraph +- `ReflectUtil` — reflective subclass and annotation utility work used during discovery +- `SysUtil` and `JavaProcess` — OS process and runtime helpers used for external launch and environment control +- shared logging and serialization helpers — they provide a common runtime foundation across modules + +These are not as central as `EventHandler` and orchestration, but they are the kinds of utilities that can quietly become critical to future maintenance work if left undocumented. + +## Summary + +If you need to understand how EOCV-Sim keeps the app coordinated without a big monolithic startup method, the answer lives in these utility layers: + +- the event system coordinates notifications and UI/runtime callbacks +- the orchestration layer coordinates lifecycle dependencies and phased initialization +- the scanning/utilities layer handles runtime discovery and environment integration + +Together they form the backbone of the software architecture and are worth reading before diving into any specific subsystem. diff --git a/documents/11-tunable-fields.md b/documents/11-tunable-fields.md new file mode 100644 index 00000000..0c161fb6 --- /dev/null +++ b/documents/11-tunable-fields.md @@ -0,0 +1,160 @@ +# Tunable fields and the tuning runtime + +The tuner system is the part of EOCV-Sim that lets you modify pipeline values while the app is running. It is one of the most important developer-facing features in the project, because it turns a static OpenCV pipeline into a live, inspectable runtime object you can adjust without restarting the simulator. + +This subsystem is centered on `TunerManager`, but it also depends on reflection helpers, field registries, and Swing UI panels. Together they provide a loop that reads field values from the active pipeline, presents them in the GUI, and writes new values back into the pipeline object when the user changes them. + +## High-level purpose + +The tuner system exists to bridge three layers: + +- the running pipeline object, +- the GUI controls shown in the visualizer, +- and the reflection metadata needed to discover and mutate fields safely. + +The app does not hardcode a list of editable pipeline values. Instead, it inspects the live pipeline instance using `VirtualReflection`, finds fields compatible with a tunable contract, and exposes them through a generic `TunableField` abstraction. + +This is why a pipeline author can simply write public fields like `blur`, `threshold`, or `colorRange` and have them appear in the tuner UI automatically. + +## `TunerManager`: the runtime coordinator + +`TunerManager` is the central coordinator for the tuning subsystem. It is registered as a lifecycle-aware object in the main app orchestration and participates in the same init/run/destroy phases used by other major managers. + +Its responsibilities are straightforward: + +- listen for pipeline changes, +- refresh the list of tunable fields for the active pipeline, +- create GUI panels for each field, +- update field values from the pipeline while it runs, +- and propagate user edits back into the live object. + +The main workflow is: + +1. `init()` attaches a listener to `pipelineManager.onPipelineChange` +2. `refreshFields()` inspects `pipelineManager.reflectTarget` +3. `addFieldsFrom(pipeline)` enumerates fields through the virtual reflection layer +4. each field is wrapped in a `TunableField` instance when a registry matches it +5. the visualizer gets a list of `TunableFieldPanel`s and shows them to the user +6. each frame, `run()` walks the field list and calls `field.update()` + +This keeps the UI synchronized with the actual runtime state, even while the pipeline is processing frames continuously. + +## Discovery: the reflection layer and registry + +The system does not discover tunable fields by scanning arbitrary Java types at runtime with ad hoc logic. Instead, it relies on the `VirtualReflection` abstraction and a registry object called `TunableFieldRegistry`. + +`TunableFieldRegistry` does two things: + +- it maps exact Java types to field handlers, such as `Integer`, `Double`, `Float`, `String`, `Boolean`, `Scalar`, `Point`, `Rect` +- it accepts additional field types through `TunableFieldAcceptor` implementations, allowing more specialized forms such as enum-backed values + +Then `TunerManager.addFieldsFrom(pipeline)` does the following: + +- gets a reflection context for the current pipeline object +- iterates the context’s `fields` +- asks `newTunableFieldInstanceFor(field, pipeline)` for a specific `TunableField` implementation +- adds it to the manager’s `fields` list if it is supported + +The registry intentionally filters out `final` fields, because they cannot be safely mutated at runtime. It also unwraps primitive values into boxed equivalents so the same type logic can be reused consistently. + +## `TunableField`: the abstraction for one editable property + +Each editable property becomes a `TunableField`. This abstraction wraps: + +- the target pipeline object, +- the reflected field (`VirtualField`), +- the permitted editing mode (`AllowMode`), +- a set of `TunableValue` objects representing each editable part of the field, +- and the `TunableFieldPanel` that renders it in the GUI. + +The base class is intentionally generic and does not assume whether the property is a number, string, boolean, or enum. It exposes a few critical hooks: + +- `init()` — called once when the field is first wired up +- `update()` — called each runtime tick to sync the actual Java field with the UI values +- `setPipelineFieldValue(newValue)` — writes the new value back into the pipeline object when the user edits it +- `tunableValues` — the actual value wrappers that are bound to the panel controls + +The manager’s `run()` loop repeatedly invokes `field.update()`, which keeps the pipeline object and the UI in sync without requiring the user to manually refresh anything. + +## `TunableValue`: a typed GUI value bridge + +A field may contain one or more editable sub-values. For example, a `Point` field might expose two numeric values, while an enum field exposes a current selected constant. + +To model that, the code uses `TunableValue` subclasses: + +- `TunableNumber` +- `TunableString` +- `TunableBoolean` +- `TunableEnum` + +Each `TunableValue` includes: + +- the current value, +- a supplier that reads the value from the pipeline, +- a consumer that writes the value back to the pipeline, +- and event hooks for pipeline-driven and GUI-driven updates. + +The important distinction is: + +- `setFromPipeline(newValue)` updates the value when the pipeline changed, +- `setFromGui(guiValue)` writes the user’s input back into the actual object, +- `onPipelineUpdate` fires when a value changes as a consequence of the pipeline, +- `onValueChange` fires when a user or runtime action modifies the wrapped value. + +This design allows the UI to react to field changes without directly mutating the pipeline at the wrong time or causing a feedback loop. + +## GUI panel layer: `TunableFieldPanel` + +The Swing UI is built by `TunableFieldPanel`. Each field gets a panel that renders the right control widgets for its data type: + +- numeric values can render as text boxes and optional sliders, +- string values render as text editors, +- enums render as combo boxes, +- and other supported values can be shown as a typed editor depending on the `TunableField` implementation. + +The panel does not just display values; it keeps the controls synchronized with the underlying field values. `setTunableFieldPanel()` wires each `TunableValue` to the panel so that when the pipeline value changes, the UI updates via Swing’s event queue. + +Important behaviors in the panel layer include: + +- switching between text-box mode and slider mode, +- applying config options such as min/max bounds or custom display settings, +- ensuring the UI does not re-enter an update loop when it is already being edited, +- and allowing a panel to request re-evaluation of all config settings. + +This is the tangible “live tuning” feature that users interact with in the simulator. + +## Configuration and field options + +The tuning system also reads configuration through the Swing panel configuration objects, especially `TunableFieldPanelConfig`. That config layer controls how tunable fields are displayed and constrained. + +This includes items such as: + +- default value ranges, +- color-space behavior for CV values, +- whether the panel is in text-box or slider mode, +- and per-field or global default options. + +The config is important because a pipeline may expose a field that should be constrained to a specific numeric range or rendered differently depending on its type. The tuning system is therefore not just raw reflection; it is a curated runtime configuration layer that tailors the value editing experience. + +## Why the system matters in EOCV-Sim + +The tuning system is one of the features that makes EOCV-Sim feel like a real vision development tool rather than a simple image viewer. It enables the app to let developers do things like: + +- slide a threshold up and down live, +- tweak a blur radius without recompiling, +- inspect and modify a pipeline field while the output updates, +- and immediately compare different parameter values in the same runtime session. + +In other words, it turns the simulator into an iterative tuning environment. The user does not need to edit source code and rebuild a pipeline just to change one parameter; they can tune it interactively. + +## Summary + +The tunable field system is a reflective, UI-driven runtime control layer built on top of the active pipeline object. The major moving pieces are: + +- `TunerManager` — lifecycle coordinator for the runtime tuning subsystem +- `TunableFieldRegistry` — type-based registration and discovery of editable fields +- `TunableField` — a generic wrapper around a reflected property +- `TunableValue` — typed read/write bridge for each field sub-value +- `TunableFieldPanel` — Swing control layer that renders and edits values + +Without this subsystem, the simulator would be much less useful as a development environment, because the user would have to recompile or restart the app after every small parameter change. diff --git a/documents/README.md b/documents/README.md new file mode 100644 index 00000000..57df7267 --- /dev/null +++ b/documents/README.md @@ -0,0 +1,59 @@ +# EOCV-Sim Architecture Documentation + +This directory contains subsystem guides for the project’s major runtime areas. The codebase is a multi-module Java/Kotlin application built around a desktop Swing UI, an OpenCV pipeline engine, a workspace-based development flow, and a plugin/security extension layer. + +## Repository structure + +- `../VisionBench/` — main simulator application module +- `Common/` — shared orchestration and utility libraries +- `Vision/` — OpenCV rendering and viewport adaptation layer +- `TeamCode/` — sample FTC-style pipeline code and examples +- `doc/` — additional project documentation and reference material + +## Documentation map + +- [01-overview-and-architecture.md](./01-overview-and-architecture.md) — project structure, lifecycle, and module responsibilities +- [02-main-eocvsim.md](./02-main-eocvsim.md) — bootstrap flow and central runtime orchestration +- [03-config-and-settings.md](./03-config-and-settings.md) — config model and user settings flow +- [04-gui-and-visualizer.md](./04-gui-and-visualizer.md) — Swing UI, control panels, and viewport host +- [05-pipeline-runtime.md](./05-pipeline-runtime.md) — active pipeline lifecycle, execution, telemetry, and exceptions +- [06-input-sources.md](./06-input-sources.md) — images, cameras, and source acquisition +- [07-workspaces.md](./07-workspaces.md) — editable project folders, compiler integration, and watch-based rebuilds +- [08-plugins-and-superaccess.md](./08-plugins-and-superaccess.md) — plugin loading, repository handling, and security prompts +- [09-vision-and-common-libraries.md](./09-vision-and-common-libraries.md) — rendering layer and foundational shared libraries +- [10-runtime-utilities.md](./10-runtime-utilities.md) — event handling, lifecycle orchestration, and shared runtime infrastructure +- [11-tunable-fields.md](./11-tunable-fields.md) — live pipeline tuning, reflection-driven field discovery, and the runtime editor system + +## Core execution path + +The runtime follows a consistent application flow: + +1. `Main.kt` launches the process. +2. `Module.kt` creates the Koin dependency graph. +3. `EOCVSim.start()` orchestrates the app lifecycle in phases. +4. Config is initialized and loaded from disk. +5. The GUI is built and the viewport is prepared. +6. Input sources and default workspaces are selected and initialized. +7. The active pipeline is chosen and run against frames from the source. +8. The output is rendered and statistics are displayed. +9. Plugins and file watching continue to operate during runtime. + +This architecture intentionally separates the “runtime engine” from the “desktop experience,” while still making them work together as one application. + +## Reading guide + +If you are new to the codebase, a practical reading order is: + +- `01-overview-and-architecture.md` +- `02-main-eocvsim.md` +- `03-config-and-settings.md` +- `05-pipeline-runtime.md` +- `06-input-sources.md` +- `04-gui-and-visualizer.md` +- `07-workspaces.md` +- `08-plugins-and-superaccess.md` +- `09-vision-and-common-libraries.md` +- `10-runtime-utilities.md` +- `11-tunable-fields.md` + +This order moves from overall architecture to runtime behavior and then to subsystems that depend on that runtime. diff --git a/gradle.properties b/gradle.properties index 93c752b9..fee1fbae 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,19 +2,19 @@ SONATYPE_HOST=CENTRAL_PORTAL RELEASE_SIGNING_ENABLED=true -POM_NAME=EOCV-Sim +POM_NAME=VisionBench POM_DESCRIPTION=Develop, test, and tune your EasyOpenCV pipelines directly on your computer with a simple GUI ! POM_INCEPTION_YEAR=2024 -POM_URL=https://docs.deltacv.org/eocv-sim +POM_URL=https://deltacv.org/visionbench POM_LICENSE_NAME=MIT License POM_LICENSE_URL=https://opensource.org/license/mit POM_LICENSE_DIST=repo -POM_SCM_URL=https://github.com/deltacv/EOCV-Sim/ -POM_SCM_CONNECTION=scm:git:git://github.com/deltacv/EOCV-Sim.git -POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/deltacv/EOCV-Sim.git +POM_SCM_URL=https://github.com/deltacv/VisionBench/ +POM_SCM_CONNECTION=scm:git:git://github.com/deltacv/VisionBench.git +POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/deltacv/VisionBench.git POM_DEVELOPER_ID=serivesmejia POM_DEVELOPER_NAME=Sebastian Erives -POM_DEVELOPER_URL=https://github.com/serivesmejia/ \ No newline at end of file +POM_DEVELOPER_URL=https://deltacv.org/people/serivesmejia \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 547da593..2463ffd6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,9 +15,9 @@ plugins { id 'org.gradle.toolchains.foojay-resolver-convention' version "0.4.0" } -rootProject.name = 'EOCV-Sim' +rootProject.name = 'VisionBench' include 'TeamCode' -include 'EOCV-Sim' +include 'VisionBench' include 'Common' include 'Vision' \ No newline at end of file