Skip to content

Commit

Permalink
[glass] Add camera support
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterJohnson committed Oct 22, 2024
1 parent fae7325 commit 57369fd
Show file tree
Hide file tree
Showing 14 changed files with 1,503 additions and 2 deletions.
23 changes: 22 additions & 1 deletion glass/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,27 @@ install(TARGETS libglassnt EXPORT libglassnt)
export(TARGETS libglassnt FILE libglassnt.cmake NAMESPACE libglassnt::)
install(DIRECTORY src/libnt/native/include/ DESTINATION "${include_dest}/glass")

#
# libglasscs
#
file(GLOB_RECURSE libglasscs_src src/libcs/native/cpp/*.cpp)

add_library(libglasscs STATIC ${libglasscs_src})
set_target_properties(libglasscs PROPERTIES DEBUG_POSTFIX "d" OUTPUT_NAME "glasscs")
set_property(TARGET libglasscs PROPERTY POSITION_INDEPENDENT_CODE ON)

set_property(TARGET libglasscs PROPERTY FOLDER "libraries")

wpilib_target_warnings(libglasscs)
target_link_libraries(libglasscs PUBLIC cscore libglassnt)

target_include_directories(libglasscs PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/libcs/native/include>
$<INSTALL_INTERFACE:${include_dest}/glass>)

install(TARGETS libglasscs EXPORT libglasscs DESTINATION "${main_lib_dest}")
install(DIRECTORY src/libcs/native/include/ DESTINATION "${include_dest}/glass")

#
# glass application
#
Expand All @@ -79,7 +100,7 @@ endif()
add_executable(glass ${glass_src} ${glass_resources_src} ${glass_rc} ${APP_ICON_MACOSX})
wpilib_link_macos_gui(glass)
wpilib_target_warnings(glass)
target_link_libraries(glass libglassnt libglass)
target_link_libraries(glass libglasscs libglassnt libglass)

if(WIN32)
set_target_properties(glass PROPERTIES WIN32_EXECUTABLE YES)
Expand Down
35 changes: 34 additions & 1 deletion glass/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,38 @@ model {
}
appendDebugPathToBinaries(binaries)
}
"${nativeName}cs"(NativeLibrarySpec) {
sources.cpp {
source {
srcDirs = ['src/libcs/native/cpp']
include '**/*.cpp'
}
exportedHeaders {
srcDirs 'src/libcs/native/include'
}
}
binaries.all {
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
it.buildable = false
return
}
if (it instanceof SharedLibraryBinarySpec) {
it.buildable = false
return
}
lib library: nativeName, linkage: 'static'
project(':ntcore').addNtcoreDependency(it, 'shared')
lib project: ':cscore', library: 'cscore', linkage: 'shared'
nativeUtils.useRequiredLibrary(it, 'opencv_shared')
lib project: ':wpinet', library: 'wpinet', linkage: 'shared'
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
lib project: ':wpimath', library: 'wpimath', linkage: 'shared'
lib project: ':wpigui', library: 'wpigui', linkage: 'static'
lib project: ':fieldImages', library: 'fieldImages', linkage: 'shared'
nativeUtils.useRequiredLibrary(it, 'imgui')
}
appendDebugPathToBinaries(binaries)
}
"${nativeName}nt"(NativeLibrarySpec) {
sources.cpp {
source {
Expand Down Expand Up @@ -157,9 +189,10 @@ model {
it.buildable = false
return
}
lib project: ':cscore', library: 'cscore', linkage: 'static'
lib library: 'glasscs', linkage: 'static'
lib library: 'glassnt', linkage: 'static'
lib library: nativeName, linkage: 'static'
lib project: ':cscore', library: 'cscore', linkage: 'static'
project(':ntcore').addNtcoreDependency(it, 'static')
lib project: ':wpinet', library: 'wpinet', linkage: 'static'
lib project: ':wpiutil', library: 'wpiutil', linkage: 'static'
Expand Down
37 changes: 37 additions & 0 deletions glass/publish.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ def libntBaseArtifactId = 'libglassnt'
def libntArtifactGroupId = 'edu.wpi.first.glass'
def libntZipBaseName = '_GROUP_edu_wpi_first_glass_ID_libglassnt_CLS'

def libcsBaseArtifactId = 'libglasscs'
def libcsArtifactGroupId = 'edu.wpi.first.glass'
def libcsZipBaseName = '_GROUP_edu_wpi_first_glass_ID_libglasscs_CLS'

def outputsFolder = file("$project.buildDir/outputs")

task libCppSourcesZip(type: Zip) {
Expand Down Expand Up @@ -50,15 +54,37 @@ task libntCppHeadersZip(type: Zip) {
from('src/libnt/native/include') { into '/' }
}

task libcsCppSourcesZip(type: Zip) {
destinationDirectory = outputsFolder
archiveBaseName = libcsZipBaseName
classifier = "sources"

from(licenseFile) { into '/' }
from('src/libcs/native/cpp') { into '/' }
}

task libcsCppHeadersZip(type: Zip) {
destinationDirectory = outputsFolder
archiveBaseName = libcsZipBaseName
classifier = "headers"

from(licenseFile) { into '/' }
from('src/libcs/native/include') { into '/' }
}

build.dependsOn libCppHeadersZip
build.dependsOn libCppSourcesZip
build.dependsOn libntCppHeadersZip
build.dependsOn libntCppSourcesZip
build.dependsOn libcsCppHeadersZip
build.dependsOn libcsCppSourcesZip

addTaskToCopyAllOutputs(libCppHeadersZip)
addTaskToCopyAllOutputs(libCppSourcesZip)
addTaskToCopyAllOutputs(libntCppHeadersZip)
addTaskToCopyAllOutputs(libntCppSourcesZip)
addTaskToCopyAllOutputs(libcsCppHeadersZip)
addTaskToCopyAllOutputs(libcsCppSourcesZip)

model {
tasks {
Expand Down Expand Up @@ -168,6 +194,7 @@ model {

def libGlassTaskList = createComponentZipTasks($.components, ['glass'], libZipBaseName, Zip, project, includeStandardZipFormat)
def libGlassntTaskList = createComponentZipTasks($.components, ['glassnt'], libntZipBaseName, Zip, project, includeStandardZipFormat)
def libGlasscsTaskList = createComponentZipTasks($.components, ['glasscs'], libcsZipBaseName, Zip, project, includeStandardZipFormat)

publications {
glassApp(MavenPublication) {
Expand Down Expand Up @@ -197,6 +224,16 @@ model {
groupId = libntArtifactGroupId
version wpilibVersioning.version.get()
}
libglasscs(MavenPublication) {
libGlasscsTaskList.each { artifact it }

artifact libcsCppHeadersZip
artifact libcsCppSourcesZip

artifactId = libcsBaseArtifactId
groupId = libcsArtifactGroupId
version wpilibVersioning.version.get()
}
}
}
}
115 changes: 115 additions & 0 deletions glass/src/app/native/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <GLFW/glfw3.h>
#include <fmt/format.h>
#include <imgui.h>
#include <cscore_cpp.h>
#include <ntcore_cpp.h>
#include <wpi/StringExtras.h>
#include <wpigui.h>
Expand All @@ -17,6 +18,9 @@
#include "glass/MainMenuBar.h"
#include "glass/Storage.h"
#include "glass/Window.h"
#include "glass/camera/Camera.h"
#include "glass/camera/NTCameraProvider.h"
#include "glass/camera/UsbCameraList.h"
#include "glass/networktables/NetworkTables.h"
#include "glass/networktables/NetworkTablesProvider.h"
#include "glass/networktables/NetworkTablesSettings.h"
Expand All @@ -39,6 +43,8 @@ std::string_view GetResource_glass_512_png();

static std::unique_ptr<glass::PlotProvider> gPlotProvider;
static std::unique_ptr<glass::NetworkTablesProvider> gNtProvider;
static std::unique_ptr<glass::NTCameraProvider> gNtCameraProvider;
static std::unique_ptr<glass::UsbCameraList> gUsbCameraList;

static std::unique_ptr<glass::NetworkTablesModel> gNetworkTablesModel;
static std::unique_ptr<glass::NetworkTablesSettings> gNetworkTablesSettings;
Expand All @@ -47,6 +53,7 @@ static glass::Window* gNetworkTablesWindow;
static glass::Window* gNetworkTablesInfoWindow;
static glass::Window* gNetworkTablesSettingsWindow;
static glass::Window* gNetworkTablesLogWindow;
static glass::Window* gCameraListWindow;

static glass::MainMenuBar gMainMenu;
static bool gAbout = false;
Expand Down Expand Up @@ -171,6 +178,41 @@ static void NtInitialize() {
});
}

static void CsInitialize() {
cs::SetTelemetryPeriod(1.0);
cs::SetLogger([](unsigned int level, const char* file, unsigned int line,
const char* msg) { fmt::print("CS: {}\n", msg); },
CS_LOG_INFO);

gNtCameraProvider = std::make_unique<glass::NTCameraProvider>(
glass::GetStorageRoot().GetChild("NT Cameras"));
gNtCameraProvider->GlobalInit();

gUsbCameraList = std::make_unique<glass::UsbCameraList>();

gCameraListWindow =
glass::imm::CreateWindow("Camera List", false, glass::Window::kHide);
gCameraListWindow->SetDefaultPos(250, 250);
gCameraListWindow->SetDefaultSize(500, 200);
gCameraListWindow->SetFlags(ImGuiWindowFlags_AlwaysAutoResize);
gui::AddWindowScaler(
[](float scale) { gCameraListWindow->ScaleDefault(scale); });

gui::AddEarlyExecute([] {
glass::Storage& cameras = glass::GetStorageRoot().GetChild("cameras");
for (auto&& storage : cameras.GetChildren()) {
glass::CameraModel* model = glass::GetCameraModel(cameras, storage.key());
if (!model) {
model = glass::GetOrNewCameraModel(cameras, storage.key());
model->Start();
}
model->Update();
}

gUsbCameraList->Update();
});
}

#ifdef _WIN32
int __stdcall WinMain(void* hInstance, void* hPrevInstance, char* pCmdLine,
int nCmdShow) {
Expand Down Expand Up @@ -212,6 +254,7 @@ int main(int argc, char** argv) {
gui::AddInit([] { glass::ResetTime(); });
gNtProvider->GlobalInit();
NtInitialize();
CsInitialize();

glass::AddStandardNetworkTablesViews(*gNtProvider);

Expand All @@ -236,6 +279,27 @@ int main(int argc, char** argv) {
gNtProvider->DisplayMenu();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Camera")) {
gCameraListWindow->DisplayMenuItem();
if (ImGui::MenuItem("New Camera View")) {
auto& viewsStorage = glass::GetStorageRoot().GetChild("camera views");
auto& views = viewsStorage.GetValues();
// this is an inefficient algorithm, but the number of windows is small
char id[32];
size_t numViews = views.size();
for (size_t i = 0; i <= numViews; ++i) {
wpi::format_to_n_c_str(id, sizeof(id), "Camera View <{}>",
static_cast<int>(i));
if (!views.contains(id)) {
break;
}
}
if (auto win = glass::imm::CreateWindow(viewsStorage, id)) {
win->SetDefaultSize(700, 400);
}
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Plot")) {
bool paused = gPlotProvider->IsPaused();
if (ImGui::MenuItem("Pause All Plots", nullptr, &paused)) {
Expand Down Expand Up @@ -300,6 +364,54 @@ int main(int argc, char** argv) {
}
glass::imm::EndWindow();

glass::Storage& cameras = glass::GetStorageRoot().GetChild("cameras");

if (glass::imm::BeginWindow(gCameraListWindow)) {
glass::DisplayCameraModelTable(cameras);
if (ImGui::Button("Add USB")) {
ImGui::OpenPopup("Add USB Camera");
}
if (ImGui::BeginPopup("Add USB Camera")) {
std::string path = gUsbCameraList->DisplayMenu();
if (!path.empty()) {
auto id = fmt::format("glass::usb::{}", path);
glass::CameraModel* model = glass::GetOrNewCameraModel(cameras, id);
if (!model->GetSource()) {
model->SetSource(cs::UsbCamera(id, path));
}
model->Start();
}
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::Button("Add HTTP");
ImGui::SameLine();
ImGui::Button("Add CameraServer");
}
glass::imm::EndWindow();

for (auto&& kv :
glass::GetStorageRoot().GetChild("camera views").GetChildren()) {
glass::PushStorageStack(kv.value());
if (!glass::imm::GetWindow()) {
glass::imm::CreateWindow(
glass::GetStorageRoot().GetChild("camera views"), kv.key());
}
if (glass::imm::BeginWindow()) {
if (glass::CameraModel* model = glass::GetCameraModel(
cameras, glass::GetStorage().GetString("camera"))) {
if (glass::imm::BeginWindowSettingsPopup()) {
glass::imm::GetWindow()->EditName();
glass::DisplayCameraSettings(model);
ImGui::EndPopup();
}
glass::DisplayCameraWindow(model);
}
}
glass::imm::EndWindow();
glass::PopStorageStack();
}

if (gAbout) {
ImGui::OpenPopup("About");
gAbout = false;
Expand Down Expand Up @@ -364,6 +476,9 @@ int main(int argc, char** argv) {
}
gui::Main();

// cs::Shutdown();
gUsbCameraList.reset();
gNtCameraProvider.reset();
gNetworkTablesModel.reset();
gNtProvider.reset();
gPlotProvider.reset();
Expand Down
Loading

0 comments on commit 57369fd

Please sign in to comment.