30 Commits

Author SHA1 Message Date
b2f27e0ec0 Update README.md 2025-09-16 23:45:24 +00:00
b4a53e4f58 Update README.md 2025-09-15 17:20:45 +00:00
fff343cdfb readme mods 2025-09-15 17:08:50 +00:00
5ccd71c285 Remove reference to git bash (no longer necessary) 2025-09-15 12:06:24 -05:00
ffd11d0995 Need the -LD flag for both configs to build a DLL. More: https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=msvc-170 2025-09-15 11:57:06 -05:00
cb6d239d00 readme mods. can build with glfw in either Debug or Release config. some reorg of the cpp example 2025-09-15 11:53:24 -05:00
6d45d12dc1 Save cs example into an actual project 2025-09-15 11:22:27 -05:00
e77dfde1bc reorganize to use .bat files instead of .sh. Move demo to an example project 2025-09-15 10:58:01 -05:00
530dea9728 fix path to LivePlotter.cs 2025-09-15 09:25:51 -05:00
8b38b8feff fix spelling mistake 2025-09-15 09:25:04 -05:00
d686ad7799 remove hacky testing script 2025-09-15 09:23:09 -05:00
11d8e9a865 move csharp example to examples folder 2025-09-15 09:22:23 -05:00
69d5ef09bf ignore future compile command files 2025-09-15 09:21:09 -05:00
2b9316f9d2 remove compile_commands.json. update glfw 2025-09-15 09:19:59 -05:00
2c20254c23 readme mods 2025-09-12 09:43:28 -05:00
90c3023618 readme mods 2025-09-11 14:47:54 -05:00
60ad2c5da5 readme mods 2025-09-11 14:37:56 -05:00
bedb7d93e9 remove unneeded files 2025-09-11 14:31:16 -05:00
7f0d52c3a0 Add readme and example csharp dll interface class. 2025-09-11 14:30:05 -05:00
6d47b81b1f demo worthy. Plenty more work could be done, but not terrible 2025-09-11 13:21:53 -05:00
2821847ce2 Can build the project. Now trying to isolate opengl problem 2025-09-11 08:23:02 -05:00
2d38f74371 saving alternate build method. About to go back to regular visual studio build, but may pursue this approach in the future 2025-09-09 09:44:15 -05:00
7c4f089f2e should refer to faces array directly (not pointer to pointer) 2025-09-06 10:52:19 -05:00
1c7a9900be pool allocation. not working. not sure why. will travel back in time... 2025-09-05 11:21:34 -05:00
75e72ba9ca cleanup build. add demo project. add timing features to sync. switch to more std::string and std::vector usage over custom, hacky Array template 2025-09-01 21:56:43 -05:00
b4e90dce4d Different local glfw buildd ¯_(ツ)_/¯ 2025-08-26 13:24:09 -05:00
d0c1d9fb93 func names are no longer mangled to death 2025-08-25 18:22:23 -05:00
e626c94f4a define DllExport inside live_plotter.hpp instead of util.hpp 2025-08-25 04:43:55 -05:00
8901a0872a refer to all directories from the project dir and not the solution dir (for instances where the solution dir is outside the project dir 2025-08-25 04:31:00 -05:00
Seth Hamilton
b79017bd43 Merge pull request #1 from shamilton801/dll-conversion
Major Refactor + Now can build to a DLL instead of a .exe
2025-08-25 04:22:37 -05:00
43 changed files with 944 additions and 2215 deletions

View File

@@ -1,8 +0,0 @@
# Format Style Options - Created with Clang Power Tools
---
BasedOnStyle: WebKit
BreakBeforeBraces: Attach
ColumnLimit: 110
SortIncludes: false
SpaceAfterTemplateKeyword: false
...

4
.gitignore vendored
View File

@@ -11,3 +11,7 @@ x64**
**.pdb
**.exe
.cache**
tags
**/bin/**
**/obj/**
compile_commands.json

View File

@@ -1,37 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35707.178
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LivePlotter", "LivePlotter.vcxproj", "{74C0F84F-216F-4A12-9F91-6AFC83CF9257}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
DLLDebug|x64 = DLLDebug|x64
DLLDebug|x86 = DLLDebug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.Debug|x64.ActiveCfg = Debug|x64
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.Debug|x64.Build.0 = Debug|x64
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.Debug|x86.ActiveCfg = Debug|Win32
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.Debug|x86.Build.0 = Debug|Win32
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.DLLDebug|x64.ActiveCfg = DebugDLL|x64
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.DLLDebug|x64.Build.0 = DebugDLL|x64
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.DLLDebug|x86.ActiveCfg = DebugDLL|Win32
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.DLLDebug|x86.Build.0 = DebugDLL|Win32
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.Release|x64.ActiveCfg = Release|x64
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.Release|x64.Build.0 = Release|x64
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.Release|x86.ActiveCfg = Release|Win32
{74C0F84F-216F-4A12-9F91-6AFC83CF9257}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C971CF76-7BA3-45CC-A602-A49CCD685470}
EndGlobalSection
EndGlobal

View File

@@ -1,216 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugDLL|Win32">
<Configuration>DebugDLL</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugDLL|x64">
<Configuration>DebugDLL</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{74c0f84f-216f-4a12-9f91-6afc83cf9257}</ProjectGuid>
<RootNamespace>LivePlotter</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LibraryPath>$(SolutionDir)lib;$(SolutionDir)ext\glfw\build\src\Debug;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)ext\glm;$(SolutionDir)ext\glfw\include;$(SolutionDir)inc;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)obj\$(Platform)\$(Configuration)\</IntDir>
<SourcePath>$(SolutionDir)src;$(SourcePath)</SourcePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|x64'">
<LibraryPath>$(SolutionDir)lib;$(SolutionDir)ext\glfw\build\src\Debug;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)ext\glm;$(SolutionDir)ext\glfw\include;$(SolutionDir)inc;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)obj\$(Platform)\$(Configuration)\</IntDir>
<SourcePath>$(SolutionDir)src;$(SourcePath)</SourcePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>glfw3.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y "$(SolutionDir)poses.csv" "$(OutDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>glfw3.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y "$(SolutionDir)poses.csv" "$(OutDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\body.cpp" />
<ClCompile Include="src\camera.cpp" />
<ClCompile Include="src\camera_poses.cpp" />
<ClCompile Include="src\glad.c" />
<ClCompile Include="src\live_plotter.cpp" />
<ClCompile Include="src\main.cpp" />
<ClCompile Include="src\shaders.cpp" />
<ClCompile Include="src\util.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\shaders.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\glad.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\body.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\camera_poses.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\camera.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\live_plotter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

34
README.md Normal file
View File

@@ -0,0 +1,34 @@
# Overview
LivePlotter is an opengl-based, 3D point plotting DLL. It is designed to be integrated into any project that needs to see 3D points plotted and updated in real time. It supports simple camera controls: rotate, pan, and zoom. Points can be given a "lifetime" during which their opacity will fade. The opacity of these points can be restored by updating their position. The goal here is to create an intuitive representation of sensor readings (where the opacity of the point represents the age of the reading).
This DLL is designed to integrate easily into a C# application. A class that accomplishes this included. See [LivePlotter.cs](./examples/csharp/LivePlotter.cs). Unfortunately the DLL also expects the presence of several other files currently, so you'll need to ensure **EVERYTHING** from the bin/ folder (that contains `LivePlotter.dll`) is in your project's build output directory.
![til](./demo.gif)
*Please note that this project is still considered a work in progress. The API may change in future revisions*
# Acquiring the DLL
There are two main ways to get the DLL...
## Download from releases (recommended)
Download the DLL from the latest release on the [releases page](https://git.the-embedded-lab.com/shamilton/LivePlotter/releases).
## Build from source (not recommended)
I don't enjoy using Visual Studio and like to manage my own build process. I prefer something simple like a script to build and that's currently what I have.
1. You'll need an installation of MSVC (likely via downloading/installing Visual Studio and then installing the C++ build tools).
2. Get the source code. `git clone --recurse-submodules https://git.the-embedded-lab.com/shamilton/LivePlotter.git`
3. Build the glfw library. `cd ext/glfw`. `mkdir build && cd build && cmake ..`. Open GLFW.sln, Change the configuration to "Release, and build the solution.
4. Find `vcvars64.bat` in your installation and modify the path in [activate.bat](./activate.bat) to point to it.
5. Open cmd.exe to the root directory of the project
6. Run `activate`. Then `build release`.
7. A folder bin/ should exist with `LivePlotter.dll` inside.
8. Copy the entire contents of the bin folder to your project's build output directory
If issues arise, please feel free to create an issue on this repository.
See the csharp and cpp [example projects](./examples) for details on how to integrate the DLL with your codebase. You must have the project built to run the csharp project (it copies the contents of bin into its output directory).

1
activate.bat Normal file
View File

@@ -0,0 +1 @@
"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"

12
build.bat Normal file
View File

@@ -0,0 +1,12 @@
@ECHO off
SET flags=-Od -ZI -MDd
SET config=Debug
IF "%1" == "release" (
SET flags=-O2 -MD
SET config=Release
)
SET srcs=src\*
mkdir bin obj
cl %srcs% ext\glfw\build\src\%config%\glfw3.lib kernel32.lib user32.lib Gdi32.lib Shell32.lib -I inc -I ext\glm -I ext\glfw\include %flags% -std:c++20 -MP -LD -Fo:obj\\ -Fe:bin\\LivePlotter.dll
COPY /Y assets\* bin
COPY /Y assets\shaders\* bin

View File

@@ -1,49 +0,0 @@
[
{
"directory": "C:/Users/seth/Documents/repos/LivePlotter/",
"command": "\"C:/Users/seth/AppData/Roaming/ClangPowerTools/LLVM_Lite/Bin/clang++.exe\" -x c++ \"C:/Users/seth/Documents/repos/LivePlotter/src/util.cpp\" -std=c++20 -Wall -fms-compatibility-version=19.10 -Wmicrosoft -Wno-invalid-token-paste -Wno-unknown-pragmas -Wno-unused-value -fsyntax-only \"-DUNICODE\" \"-D_UNICODE\" \"-D_MT\" \"-D_DLL\" \"-D_DEBUG\" \"-D_CONSOLE\" \"-D_DEBUG_FUNCTIONAL_MACHINERY\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/atlmfc/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Auxiliary/VS/include\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/ucrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/shared\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/winrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/cppwinrt\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/pthreads4w-code\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glm\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glfw/include\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/inc\"",
"file": "C:/Users/seth/Documents/repos/LivePlotter/src/util.cpp"
}
,
{
"directory": "C:/Users/seth/Documents/repos/LivePlotter/",
"command": "\"C:/Users/seth/AppData/Roaming/ClangPowerTools/LLVM_Lite/Bin/clang++.exe\" -x c++ \"C:/Users/seth/Documents/repos/LivePlotter/src/camera_poses.cpp\" -std=c++20 -Wall -fms-compatibility-version=19.10 -Wmicrosoft -Wno-invalid-token-paste -Wno-unknown-pragmas -Wno-unused-value -fsyntax-only \"-DUNICODE\" \"-D_UNICODE\" \"-D_MT\" \"-D_DLL\" \"-D_DEBUG\" \"-D_CONSOLE\" \"-D_DEBUG_FUNCTIONAL_MACHINERY\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/atlmfc/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Auxiliary/VS/include\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/ucrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/shared\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/winrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/cppwinrt\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/pthreads4w-code\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glm\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glfw/include\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/inc\"",
"file": "C:/Users/seth/Documents/repos/LivePlotter/src/camera_poses.cpp"
}
,
{
"directory": "C:/Users/seth/Documents/repos/LivePlotter/",
"command": "\"C:/Users/seth/AppData/Roaming/ClangPowerTools/LLVM_Lite/Bin/clang++.exe\" -x c++ \"C:/Users/seth/Documents/repos/LivePlotter/src/shaders.cpp\" -std=c++20 -Wall -fms-compatibility-version=19.10 -Wmicrosoft -Wno-invalid-token-paste -Wno-unknown-pragmas -Wno-unused-value -fsyntax-only \"-DUNICODE\" \"-D_UNICODE\" \"-D_MT\" \"-D_DLL\" \"-D_DEBUG\" \"-D_CONSOLE\" \"-D_DEBUG_FUNCTIONAL_MACHINERY\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/atlmfc/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Auxiliary/VS/include\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/ucrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/shared\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/winrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/cppwinrt\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/pthreads4w-code\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glm\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glfw/include\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/inc\"",
"file": "C:/Users/seth/Documents/repos/LivePlotter/src/shaders.cpp"
}
,
{
"directory": "C:/Users/seth/Documents/repos/LivePlotter/",
"command": "\"C:/Users/seth/AppData/Roaming/ClangPowerTools/LLVM_Lite/Bin/clang++.exe\" -x c++ \"C:/Users/seth/Documents/repos/LivePlotter/src/body.cpp\" -std=c++20 -Wall -fms-compatibility-version=19.10 -Wmicrosoft -Wno-invalid-token-paste -Wno-unknown-pragmas -Wno-unused-value -fsyntax-only \"-DUNICODE\" \"-D_UNICODE\" \"-D_MT\" \"-D_DLL\" \"-D_DEBUG\" \"-D_CONSOLE\" \"-D_DEBUG_FUNCTIONAL_MACHINERY\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/atlmfc/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Auxiliary/VS/include\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/ucrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/shared\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/winrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/cppwinrt\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/pthreads4w-code\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glm\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glfw/include\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/inc\"",
"file": "C:/Users/seth/Documents/repos/LivePlotter/src/body.cpp"
}
,
{
"directory": "C:/Users/seth/Documents/repos/LivePlotter/",
"command": "\"C:/Users/seth/AppData/Roaming/ClangPowerTools/LLVM_Lite/Bin/clang++.exe\" -x c++ \"C:/Users/seth/Documents/repos/LivePlotter/src/live_plotter.cpp\" -std=c++20 -Wall -fms-compatibility-version=19.10 -Wmicrosoft -Wno-invalid-token-paste -Wno-unknown-pragmas -Wno-unused-value -fsyntax-only \"-DUNICODE\" \"-D_UNICODE\" \"-D_MT\" \"-D_DLL\" \"-D_DEBUG\" \"-D_CONSOLE\" \"-D_DEBUG_FUNCTIONAL_MACHINERY\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/atlmfc/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Auxiliary/VS/include\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/ucrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/shared\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/winrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/cppwinrt\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/pthreads4w-code\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glm\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glfw/include\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/inc\"",
"file": "C:/Users/seth/Documents/repos/LivePlotter/src/live_plotter.cpp"
}
,
{
"directory": "C:/Users/seth/Documents/repos/LivePlotter/",
"command": "\"C:/Users/seth/AppData/Roaming/ClangPowerTools/LLVM_Lite/Bin/clang++.exe\" -x c++ \"C:/Users/seth/Documents/repos/LivePlotter/src/main.cpp\" -std=c++20 -Wall -fms-compatibility-version=19.10 -Wmicrosoft -Wno-invalid-token-paste -Wno-unknown-pragmas -Wno-unused-value -fsyntax-only \"-DUNICODE\" \"-D_UNICODE\" \"-D_MT\" \"-D_DLL\" \"-D_DEBUG\" \"-D_CONSOLE\" \"-D_DEBUG_FUNCTIONAL_MACHINERY\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/atlmfc/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Auxiliary/VS/include\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/ucrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/shared\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/winrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/cppwinrt\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/pthreads4w-code\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glm\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glfw/include\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/inc\"",
"file": "C:/Users/seth/Documents/repos/LivePlotter/src/main.cpp"
}
,
{
"directory": "C:/Users/seth/Documents/repos/LivePlotter/",
"command": "\"C:/Users/seth/AppData/Roaming/ClangPowerTools/LLVM_Lite/Bin/clang++.exe\" -x c \"C:/Users/seth/Documents/repos/LivePlotter/src/glad.c\" -Wall -fms-compatibility-version=19.10 -Wmicrosoft -Wno-invalid-token-paste -Wno-unknown-pragmas -Wno-unused-value -fsyntax-only \"-DUNICODE\" \"-D_UNICODE\" \"-D_MT\" \"-D_DLL\" \"-D_DEBUG\" \"-D_CONSOLE\" \"-D_DEBUG_FUNCTIONAL_MACHINERY\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/atlmfc/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Auxiliary/VS/include\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/ucrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/shared\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/winrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/cppwinrt\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/pthreads4w-code\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glm\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glfw/include\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/inc\"",
"file": "C:/Users/seth/Documents/repos/LivePlotter/src/glad.c"
}
,
{
"directory": "C:/Users/seth/Documents/repos/LivePlotter/",
"command": "\"C:/Users/seth/AppData/Roaming/ClangPowerTools/LLVM_Lite/Bin/clang++.exe\" -x c++ \"C:/Users/seth/Documents/repos/LivePlotter/src/camera.cpp\" -std=c++20 -Wall -fms-compatibility-version=19.10 -Wmicrosoft -Wno-invalid-token-paste -Wno-unknown-pragmas -Wno-unused-value -fsyntax-only \"-DUNICODE\" \"-D_UNICODE\" \"-D_MT\" \"-D_DLL\" \"-D_DEBUG\" \"-D_CONSOLE\" \"-D_DEBUG_FUNCTIONAL_MACHINERY\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/atlmfc/include\" -isystem\"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Auxiliary/VS/include\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/ucrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/shared\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/winrt\" -isystem\"C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/cppwinrt\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/pthreads4w-code\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glm\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/ext/glfw/include\" -isystem\"C:/Users/seth/Documents/repos/LivePlotter/inc\"",
"file": "C:/Users/seth/Documents/repos/LivePlotter/src/camera.cpp"
}
]

BIN
demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 KiB

View File

12
examples/cpp/build.bat Normal file
View File

@@ -0,0 +1,12 @@
SET flags=-Od -ZI -MD
IF "%1" == "release" (
SET flags=-O2 -MT
)
SET srcs=src\*
mkdir bin obj
(
PUSHD ..\..
CALL build.bat %1
POPD
COPY /Y ..\..\bin\* bin && cl %srcs% bin\LivePlotter.lib -I ..\..\inc -I ..\..\ext\glm %flags% -std:c++20 -MP -Fo:obj\\ -Fe:bin\\
)

22
examples/cpp/export.bat Normal file
View File

@@ -0,0 +1,22 @@
@ECHO off
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO [ > compile_commands.json
FOR /r "src\" %%F IN (*.cpp) DO (
SET "file=%%F"
SET "file=!file:\=/!"
SET "directory=%~dp0"
SET "directory=!directory:\=/!"
ECHO { >> compile_commands.json
ECHO "directory": "!directory!", >> compile_commands.json
ECHO "command": "cl !file! -I inc -I ../../ext/glm -I ../../ext/glfw/include %flags% -std:c++20 -MD -MP -Fo:obj\\ ", >> compile_commands.json
ECHO "file": "!file!" >> compile_commands.json
ECHO }, >> compile_commands.json
)
ECHO ] >> compile_commands.json

93
examples/cpp/src/demo.cpp Normal file
View File

@@ -0,0 +1,93 @@
#include <iostream>
#include <string>
#include <map>
#include "glm/ext/vector_float3.hpp"
#include "util.hpp"
#include "live_plotter.hpp"
#pragma comment(lib, "LivePlotter.lib")
using namespace std;
static map<string, pointid> name_to_id;
#define LINE_BUF_SIZE 256
#define NUM_SPHERES_PER_AXE 25
#define SPACE_PER_SPHERE 10.0f
bool parse_poses(std::vector<glm::mat2x3>& locs_out, const char* filepath) {
ifstream file(filepath);
if (!file.is_open()) {
return false;
}
string line;
getline(file, line);
while (getline(file, line)) {
std::vector<std::string> words = split_str(line, ',');
float x = stof(words[0]);
float y = stof(words[1]);
float z = stof(words[2]);
float w = stof(words[3]);
float i = stof(words[4]);
float j = stof(words[5]);
float k = stof(words[6]);
glm::mat4 pose = quat_to_mat4(glm::quat(w, i, j, k));
pose[3] = glm::vec4(x, y, z, 1);
// Generate axis spheres
for (int m = 0; m < 3; m++) {
for (int n = 0; n < NUM_SPHERES_PER_AXE; n++) {
glm::mat2x3 loc_color = glm::mat2x3(0.0);
loc_color[0][m] = n * SPACE_PER_SPHERE;
loc_color[0] = pose * glm::vec4(loc_color[0], 1);
loc_color[1] = glm::vec3(0);
loc_color[1][m] = 1.0f;
locs_out.push_back(loc_color);
}
}
}
return true;
}
int main() {
vector<glm::mat2x3> camera_pose_axes;
if (!parse_poses(camera_pose_axes, "poses.csv")) {
return -1;
}
start(800, 800);
for (int i = 0; i < camera_pose_axes.size(); i++) {
glm::vec3 p = camera_pose_axes[i][0];
glm::vec3 color = camera_pose_axes[i][1];
pointid id = create_point(p.x, p.y, p.z);
set_color(id, color.x, color.y, color.z);
set_scale(id, 10);
}
while (true) {
string line;
getline(cin, line);
vector<string> words = split_str(line, ' ');
if (words.size() != 4)
return NULL;
printf("Received: %s, %s, %s, %s\n", words[0].c_str(), words[1].c_str(), words[2].c_str(),
words[3].c_str()); // echo for debugging
string name = words[0];
float x = stof(words[1]);
float y = stof(words[2]);
float z = stof(words[3]);
if (auto it = name_to_id.find(name); it != name_to_id.end()) {
update_point(it->second, x, y, z);
} else {
name_to_id[name] = create_point(x, y, z);
set_lifetime(name_to_id[name], 0.2);
set_scale(name_to_id[name], 15);
}
}
}

40
examples/cpp/src/util.cpp Normal file
View File

@@ -0,0 +1,40 @@
#include "util.hpp"
using namespace std;
bool read_file(string* s, const char* filepath) {
ifstream file(filepath);
if (!file.is_open()) {
return false;
}
*s = { istreambuf_iterator<char>(file), istreambuf_iterator<char>() };
return true;
}
vector<string> split_str(string s, char delim) {
vector<string> res;
string cur_word;
istringstream ss(s);
while (getline(ss, cur_word, delim)) {
res.push_back(cur_word);
}
return res;
}
// https://songho.ca/opengl/gl_quaternion.html
glm::mat4 quat_to_mat4(glm::quat q) {
glm::vec4 col0 = glm::vec4(
1 - 2 * q.y * q.y - 2 * q.z * q.z, 2 * q.x * q.y + 2 * q.w * q.z, 2 * q.x * q.z - 2 * q.w * q.y, 0);
glm::vec4 col1 = glm::vec4(
2 * q.x * q.y - 2 * q.w * q.z, 1 - 2 * q.x * q.x - 2 * q.z * q.z, 2 * q.y * q.z + 2 * q.w * q.x, 0);
glm::vec4 col2 = glm::vec4(
2 * q.x * q.z + 2 * q.w * q.y, 2 * q.y * q.z - 2 * q.w * q.x, 1 - 2 * q.x * q.x - 2 * q.y * q.y, 0);
glm::vec4 col3 = glm::vec4(0, 0, 0, 1);
return glm::mat4(col0, col1, col2, col3);
}
float randf() { return (float)abs(rand()) / (float)RAND_MAX; }

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="COPY /Y ..\..\bin\* $(OutDir)" />
</Target>
</Project>

25
examples/csharp/Demo.sln Normal file
View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36429.23 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "Demo.csproj", "{EBDDE3D7-AF12-4A1F-B099-0D046C271859}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EBDDE3D7-AF12-4A1F-B099-0D046C271859}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBDDE3D7-AF12-4A1F-B099-0D046C271859}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBDDE3D7-AF12-4A1F-B099-0D046C271859}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBDDE3D7-AF12-4A1F-B099-0D046C271859}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1E4249FD-1F82-4EE1-AF0B-68CAB69466C7}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,68 @@
using System;
using System.Numerics;
using System.Runtime.InteropServices;
using PointID = System.UInt64;
namespace Demo
{
public class LivePlotter
{
[DllImport("LivePlotter.dll")]
public static extern bool start(int win_w, int win_h);
[DllImport("LivePlotter.dll")]
public static extern bool stop();
[DllImport("LivePlotter.dll")]
public static extern PointID create_point(float x, float y, float z);
[DllImport("LivePlotter.dll")]
public static extern void set_color(PointID id, float r, float g, float b);
[DllImport("LivePlotter.dll")]
public static extern void set_scale(PointID id, float scale);
[DllImport("LivePlotter.dll")]
public static extern void update_point(PointID id, float x, float y, float z);
[DllImport("LivePlotter.dll")]
public static extern void set_lifetime(PointID id, float new_lifetime_s);
[DllImport("LivePlotter.dll")]
public static extern void clear_point(PointID id);
public static void PlotCameraPoses()
{
string[] lines = File.ReadAllLines("poses.csv");
for (int camera_i = 1; camera_i < lines.Length; camera_i++)
{
string[] words = lines[camera_i].Split(',');
float x = float.Parse(words[0]);
float y = float.Parse(words[1]);
float z = float.Parse(words[2]);
float w = float.Parse(words[3]);
float i = float.Parse(words[4]);
float j = float.Parse(words[5]);
float k = float.Parse(words[6]);
Pose pose = new(new Quaternion(i, j, k, w), new Vector3(x, y, z));
for (int m = 0; m < 3; m++)
{
for (int n = 0; n < 25; n++)
{
Vector3 local = new(0);
local[m] = n * 10.0f;
Vector3 global = pose * local;
PointID id = create_point(global.X, global.Y, global.Z);
Vector3 color = new(0);
color[m] = 1.0f;
set_color(id, color.X, color.Y, color.Z);
set_scale(id, 15);
}
}
}
}
}
}

40
examples/csharp/Pose.cs Normal file
View File

@@ -0,0 +1,40 @@
using System.Numerics;
namespace Demo
{
/// <summary>
/// <para>
/// Represents a rigid transformation from one coordinate system to another. <b>NOTE: By default, unless otherwise
/// stated, the <c>Pose</c> of an object transforms its local space to the ambient world space. </b>
/// </para>
/// <para>
/// Given two <c>Pose</c>s <c>p1</c> and <c>p2</c> which transform from space A to B and from B to C respectively,
/// the pose <c>p2 * p1</c> transforms from A to C, and <c>p1 * v</c> transforms a vector <c>v</c> from space A to
/// B. A <c>Pose</c> has a rotation and a translation. The rotation is always applied first, followed by the
/// translation.
/// </para>
/// </summary>
/// <param name="rotation">The rotation of this pose.</param>
/// <param name="translation">The translation of this pose.</param>
public struct Pose(Quaternion rotation, Vector3 translation)
{
public Vector3 Translation { readonly get; set; } = translation;
public Quaternion Rotation { readonly get; set; } = rotation;
public static Pose Identity => new(Quaternion.Identity, Vector3.Zero);
public Pose(Vector3 translation) : this(Quaternion.Identity, translation) { }
public Pose(Quaternion rotation) : this(rotation, Vector3.Zero) { }
public static Vector3 operator *(Pose p, Vector3 v) => Vector3.Transform(v, p.Rotation) + p.Translation;
public static Pose operator *(Pose a, Pose b) => new(a.Rotation * b.Rotation, a * b.Translation);
public readonly Pose Inverse
{
get
{
var rotInv = Quaternion.Conjugate(Rotation);
return new(rotInv, -Vector3.Transform(Translation, rotInv));
}
}
}
}

View File

@@ -0,0 +1,6 @@
using Demo;
LivePlotter.start(800, 800);
LivePlotter.PlotCameraPoses();
while (true) ;

22
export.bat Normal file
View File

@@ -0,0 +1,22 @@
@ECHO off
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO [ > compile_commands.json
FOR /r "src\" %%F IN (*.cpp) DO (
SET "file=%%F"
SET "file=!file:\=/!"
SET "directory=%~dp0"
SET "directory=!directory:\=/!"
ECHO { >> compile_commands.json
ECHO "directory": "!directory!", >> compile_commands.json
ECHO "command": "cl !file! -I inc -I ext/glm -I ext/glfw/include %flags% -std:c++20 -MP -LD -Fo:obj\\ ", >> compile_commands.json
ECHO "file": "!file!" >> compile_commands.json
ECHO }, >> compile_commands.json
)
ECHO ] >> compile_commands.json

File diff suppressed because it is too large Load Diff

View File

@@ -2,20 +2,27 @@
#include <glm/ext/matrix_float4x4.hpp>
#include <glm/glm.hpp>
#include <string>
#include "util.hpp"
struct ObjData {
float* verts;
int verts_len;
int* faces;
int faces_len;
};
struct Body {
glm::mat4 pose;
glm::vec4 color;
float scale;
uint ebo;
uint vao;
uint vbo;
uint shader;
Array<float> verts;
Array<int> faces;
glm::vec4 color;
ObjData data;
};
bool load_body(Body* out_body, const char* obj_filepath);
bool load_body(Body* out_body, std::string filepath);
void draw_body(const Body& b);
void create_new_sphere(Body* b, float scale=1.0f);
void create_new_sphere(Body* b, float scale, glm::vec4 color);

View File

@@ -1,5 +1,3 @@
#pragma once
#include "util.hpp"
bool parse_poses(Array<glm::mat2x3>* locs_out, const char* filepath);
bool parse_poses(std::vector<glm::mat2x3>* locs_out, const char* filepath);

97
inc/gldebug.hpp Normal file
View File

@@ -0,0 +1,97 @@
#pragma once
#include <stdio.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
void APIENTRY gl_debug_cb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam)
{
// Some debug messages are just annoying informational messages
switch (id)
{
case 131185: // glBufferData
return;
}
printf("Message: %s\n", message);
printf("Source: ");
switch (source)
{
case GL_DEBUG_SOURCE_API:
printf("API");
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
printf("Window System");
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER:
printf("Shader Compiler");
break;
case GL_DEBUG_SOURCE_THIRD_PARTY:
printf("Third Party");
break;
case GL_DEBUG_SOURCE_APPLICATION:
printf("Application");
break;
case GL_DEBUG_SOURCE_OTHER:
printf("Other");
break;
}
printf("\n");
printf("Type: ");
switch (type)
{
case GL_DEBUG_TYPE_ERROR:
printf("Error");
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
printf("Deprecated Behavior");
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
printf("Undefined Behavior");
break;
case GL_DEBUG_TYPE_PORTABILITY:
printf("Portability");
break;
case GL_DEBUG_TYPE_PERFORMANCE:
printf("Performance");
break;
case GL_DEBUG_TYPE_MARKER:
printf("Marker");
break;
case GL_DEBUG_TYPE_PUSH_GROUP:
printf("Push Group");
break;
case GL_DEBUG_TYPE_POP_GROUP:
printf("Pop Group");
break;
case GL_DEBUG_TYPE_OTHER:
printf("Other");
break;
}
printf("\n");
printf("ID: %d\n", id);
printf("Severity: ");
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH:
printf("High");
break;
case GL_DEBUG_SEVERITY_MEDIUM:
printf("Medium");
break;
case GL_DEBUG_SEVERITY_LOW:
printf("Low");
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
printf("Notification");
break;
}
printf("\n\n");
}

View File

@@ -1,12 +1,16 @@
#pragma once
#define DllExport __declspec( dllexport )
typedef unsigned long long pointid;
DllExport bool __cdecl start(int win_w, int win_h);
DllExport bool __cdecl stop();
DllExport pointid __cdecl create_point(float x, float y, float z);
DllExport void __cdecl set_color(pointid id, float r, float g, float b);
DllExport void __cdecl set_scale(pointid id, float scale);
DllExport void __cdecl update_point(pointid id, float x, float y, float z);
DllExport void __cdecl set_lifetime(pointid id, float new_lifetime_s);
DllExport void __cdecl clear_point(pointid id);
extern "C" {
DllExport bool __cdecl start(int win_w, int win_h);
DllExport bool __cdecl stop();
DllExport pointid __cdecl create_point(float x, float y, float z);
DllExport void __cdecl set_color(pointid id, float r, float g, float b);
DllExport void __cdecl set_scale(pointid id, float scale);
DllExport void __cdecl update_point(pointid id, float x, float y, float z);
DllExport void __cdecl set_lifetime(pointid id, float new_lifetime_s);
DllExport void __cdecl clear_point(pointid id);
}

190
inc/sync.hpp Normal file
View File

@@ -0,0 +1,190 @@
#pragma once
#ifdef _WIN32
#include "windows.h"
#endif
namespace sync {
#ifdef _WIN32
typedef CRITICAL_SECTION Mutex;
typedef CONDITION_VARIABLE ConditionVar;
typedef HANDLE Semaphore;
typedef HANDLE Thread;
typedef LARGE_INTEGER TimeSpan;
typedef DWORD (WINAPI *ThreadFunc)(_In_ LPVOID lpParameter);
typedef LPVOID ThreadArg;
const TimeSpan infinite_ts = { .QuadPart = LLONG_MAX };
LARGE_INTEGER _init_freq() {
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
return freq;
}
static LARGE_INTEGER freq = _init_freq();
#endif
Thread make_thread(ThreadFunc t, ThreadArg a);
void join(Thread t);
Mutex make_mutex();
void lock(Mutex &m);
bool trylock(Mutex &m);
void unlock(Mutex &m);
void dispose(Mutex &m);
ConditionVar make_condition_var();
void wait(ConditionVar &c, Mutex &m, TimeSpan ts);
void wake_one(ConditionVar &c);
void wake_all(ConditionVar &c);
void dispose(ConditionVar &c);
Semaphore make_semaphore(int initial, int max);
void wait(Semaphore &s);
void post(Semaphore &s);
void dispose(Semaphore &s);
TimeSpan from_ms(double milliseconds);
TimeSpan from_s(double seconds);
TimeSpan from_min(double minutes);
TimeSpan from_hours(double hours);
TimeSpan now();
TimeSpan operator-(const TimeSpan &a, const TimeSpan &b);
double to_ms(TimeSpan &sp);
double to_s(TimeSpan &sp);
double to_min(TimeSpan &sp);
double to_hours(TimeSpan &sp);
#ifdef _WIN32
Thread make_thread(ThreadFunc f, ThreadArg a) {
DWORD tid;
return CreateThread(NULL, 0, f, a, 0, &tid);
}
void join(Thread t) {
WaitForSingleObject(t, INFINITE);
}
Mutex make_mutex() {
Mutex m;
InitializeCriticalSection(&m);
return m;
}
void lock(Mutex &m) {
EnterCriticalSection(&m);
}
bool trylock(Mutex &m) {
return TryEnterCriticalSection(&m);
}
void unlock(Mutex &m) {
LeaveCriticalSection(&m);
}
void dispose(Mutex &m) {
DeleteCriticalSection(&m);
}
ConditionVar make_condition_var() {
ConditionVar c;
InitializeConditionVariable(&c);
return c;
}
void wait(ConditionVar &c, Mutex &m, TimeSpan ts) {
if (ts.QuadPart == infinite_ts.QuadPart) {
SleepConditionVariableCS(&c, &m, INFINITE);
} else {
SleepConditionVariableCS(&c, &m, static_cast<DWORD>(to_ms(ts)));
}
}
void wake_one(ConditionVar &c) {
WakeConditionVariable(&c);
}
void wake_all(ConditionVar &c) {
WakeAllConditionVariable(&c);
}
void dispose(ConditionVar &c) {
return; // Windows doesn't have a delete condition variable func
}
Semaphore make_semaphore(int initial, int max) {
return CreateSemaphoreA(NULL, (long)initial, (long)max, NULL);
}
void wait(Semaphore &s) {
WaitForSingleObject(s, INFINITE);
}
void post(Semaphore &s) {
ReleaseSemaphore(s, 1, NULL);
}
void dispose(Semaphore &s) {
CloseHandle(s);
}
TimeSpan from_ms(double milliseconds) {
TimeSpan ts;
ts.QuadPart = static_cast<LONGLONG>(milliseconds/1000.0)*freq.QuadPart;
return ts;
}
TimeSpan from_s(double seconds) {
TimeSpan ts;
ts.QuadPart = static_cast<LONGLONG>(seconds)*freq.QuadPart;
return ts;
}
TimeSpan from_min(double minutes) {
TimeSpan ts;
ts.QuadPart = static_cast<LONGLONG>(minutes*60.0)*freq.QuadPart;
return ts;
}
TimeSpan from_hours(double hours) {
TimeSpan ts;
ts.QuadPart = static_cast<LONGLONG>(hours*60.0*60.0)*freq.QuadPart;
return ts;
}
TimeSpan now() {
TimeSpan ts;
QueryPerformanceCounter(&ts);
return ts;
}
TimeSpan operator-(const TimeSpan &a, TimeSpan &b) {
TimeSpan ts;
ts.QuadPart = a.QuadPart - b.QuadPart;
return ts;
}
double to_ms(TimeSpan &sp) {
return static_cast<double>(sp.QuadPart*1000)/static_cast<double>(freq.QuadPart);
}
double to_s(TimeSpan &sp) {
return static_cast<double>(sp.QuadPart)/static_cast<double>(freq.QuadPart);
}
double to_min(TimeSpan &sp) {
return static_cast<double>(sp.QuadPart)/static_cast<double>(freq.QuadPart*60);
}
double to_hours(TimeSpan &sp) {
return static_cast<double>(sp.QuadPart)/static_cast<double>(freq.QuadPart*60*60);
}
#endif
} // namespace sync

View File

@@ -2,32 +2,21 @@
#include <stdio.h>
#include <cstdlib>
#include <string>
#include <fstream>
#include <sstream>
#include <glm/ext/matrix_float4x4.hpp>
#include <glm/ext/quaternion_float.hpp>
#include <glm/ext/vector_float4.hpp>
#define DllExport __declspec( dllexport )
typedef unsigned int uint;
template<class T> struct Array {
T* data;
size_t len;
size_t cap;
inline T& operator[](int i) { return data[i]; }
};
template<class T> void append(Array<T>& a, T el);
template<class T> T pop(Array<T>& a);
template<class T> void resize(Array<T>& a, size_t new_cap);
template<class T> void clear(Array<T>& a);
bool read_file(Array<char>* out, const char* filepath);
Array<char*> split_str(const char* s, char delimiter);
Array<char*> split_str(const char* s);
using namespace std;
bool read_file(string* s, const char* filepath);
vector<string> split_str(string s, char delim);
glm::mat4 quat_to_mat4(glm::quat q);
float randf();
template<class T> T lerp(T start, T end, float t) { return t * end + (1 - t) * start; }
template<class T> float ilerp(T start, T end, T pos) { return (pos - start) / (end - start); }
float randf(); // returns a float between 0 and 1

BIN
lib/WS2_32.Lib (Stored with Git LFS)

Binary file not shown.

View File

@@ -1,9 +1,14 @@
#include <cassert>
#include <glad/glad.h>
#include <map>
#include <string>
#include "util.hpp"
#include "body.hpp"
#include "shaders.hpp"
using namespace std;
enum class ParserState {
PREFIX,
VERTEX,
@@ -11,72 +16,24 @@ enum class ParserState {
FACE_SKIP,
};
static map<string, ObjData> cache;
bool _parse_obj(ObjData* data, const char* obj_filepath);
bool load_body(Body* out_body, const char* obj_filepath) {
Array<char> source;
if (!read_file(&source, obj_filepath)) {
ObjData data;
if (auto it = cache.find(obj_filepath); it != cache.end()) {
data = it->second;
} else if (_parse_obj(&data, obj_filepath)) {
cache[obj_filepath] = data;
} else {
return false;
}
size_t num_verts = 0;
size_t num_faces = 0;
for (int i = 1; i < source.len; i++) {
if (source[i] == ' ' && source[i - 1] == 'v') {
num_verts++;
} else if (source[i] == ' ' && source[i - 1] == 'f') {
num_faces++;
}
}
Array<float> verts = { (float*)malloc(sizeof(float) * num_verts * 3), num_verts * 3 };
Array<int> faces = { (int*)malloc(sizeof(int) * num_faces * 3), num_faces*3 };
// Get ready for the parsing loop
ParserState state = ParserState::PREFIX;
int vert_i = 0;
int face_i = 0;
int start = 0;
for (int i = 1; i < source.len; i++) {
switch (state) {
case ParserState::PREFIX:
if (source[i - 1] == 'v' && source[i] == ' ') {
state = ParserState::VERTEX;
start = i + 1;
} else if (i > 0 && source[i - 1] == 'f' && source[i] == ' ') {
state = ParserState::FACE;
start = i + 1;
}
break;
case ParserState::VERTEX:
if (iswspace(source[i])) {
verts[vert_i] = atof(&source[start]);
vert_i++;
start = i + 1;
}
break;
case ParserState::FACE:
if (source[i] == '/') {
state = ParserState::FACE_SKIP;
faces[face_i] = atoi(&source[start]) - 1;
face_i++;
}
break;
case ParserState::FACE_SKIP:
if (iswspace(source[i])) {
state = ParserState::FACE;
start = i + 1;
}
}
if (source[i] == '\n' || source[i] == '\r') {
state = ParserState::PREFIX;
continue;
}
}
// Need a good validation check here. This is a stand in.
if (verts.len == 0 || faces.len == 0) {
printf(
"Obj file appears incomplete or corrupted. Num verts %zu. Num Faces %zu.\n", verts.len, faces.len);
if (data.verts_len == 0 || data.faces_len == 0) {
printf("Obj file appears incomplete or corrupted. Num verts %d. Num Faces %d.\n", data.verts_len,
data.faces_len);
return false;
}
@@ -92,22 +49,15 @@ bool load_body(Body* out_body, const char* obj_filepath) {
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, verts.len * sizeof(float), verts.data, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, data.verts_len * sizeof(float), data.verts, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, faces.len * sizeof(int), faces.data, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.faces_len * sizeof(int), data.faces, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
out_body->pose = glm::mat4(1);
out_body->ebo = ebo;
out_body->vao = vao;
out_body->vbo = vbo;
out_body->shader = 0;
out_body->verts = verts;
out_body->faces = faces;
*out_body = { .pose = glm::mat4(1), .ebo = ebo, .vao = vao, .vbo = vbo, .shader = 0, .data = data };
return true;
}
@@ -116,10 +66,77 @@ void draw_body(const Body& b) {
set_uniform(b.shader, "global_t", glm::scale(b.pose, glm::vec3(b.scale)));
set_uniform(b.shader, "color", b.color);
glBindVertexArray(b.vao);
glDrawElements(GL_TRIANGLES, b.faces.len, GL_UNSIGNED_INT, 0);
glDrawElements(GL_TRIANGLES, b.data.faces_len, GL_UNSIGNED_INT, 0);
}
void create_new_sphere(Body* b, float scale) {
void create_new_sphere(Body* b, float scale, glm::vec4 color) {
assert(load_body(b, "Icosphere.obj"));
b->scale = scale;
b->color = color;
}
// I need to write a good obj file parser at some point. This is basically garbage
bool _parse_obj(ObjData* data, const char* obj_filepath) {
string source;
if (!read_file(&source, obj_filepath)) {
return {};
}
size_t num_verts = 0;
size_t num_faces = 0;
for (int i = 1; i < source.size(); i++) {
if (source[i] == ' ' && source[i - 1] == 'v') {
num_verts++;
} else if (source[i] == ' ' && source[i - 1] == 'f') {
num_faces++;
}
}
float* verts = (float*)malloc(sizeof(float) * num_verts * 3);
int* faces = (int*)malloc(sizeof(int) * num_faces * 3);
int vert_i = 0;
int face_i = 0;
// Get ready for the parsing loop
ParserState state = ParserState::PREFIX;
int start = 0;
for (int i = 1; i < source.size(); i++) {
switch (state) {
case ParserState::PREFIX:
if (source[i - 1] == 'v' && source[i] == ' ') {
state = ParserState::VERTEX;
start = i + 1;
} else if (i > 0 && source[i - 1] == 'f' && source[i] == ' ') {
state = ParserState::FACE;
start = i + 1;
}
break;
case ParserState::VERTEX:
if (iswspace(source[i])) {
verts[vert_i++] = atof(&source[start]);
start = i + 1;
}
break;
case ParserState::FACE:
if (source[i] == '/') {
state = ParserState::FACE_SKIP;
faces[face_i++] = atoi(&source[start]) - 1;
}
break;
case ParserState::FACE_SKIP:
if (iswspace(source[i])) {
state = ParserState::FACE;
start = i + 1;
}
}
if (source[i] == '\n' || source[i] == '\r') {
state = ParserState::PREFIX;
continue;
}
}
*data = { .verts = verts, .verts_len = vert_i, .faces = faces, .faces_len = face_i };
return true;
}

View File

@@ -42,7 +42,8 @@ glm::mat4 world_to_camera(Camera& c) {
glm::mat4 rotation_theta = glm::rotate(glm::mat4(1), c.theta, {0, 1, 0});
glm::mat4 rotation_phi = glm::rotate(glm::mat4(1), c.phi, {1, 0, 0});
glm::mat4 rotated_focus_to_camera = glm::translate(glm::mat4(1), { 0, 0, -c.distance });
return rotated_focus_to_camera * rotation_phi * rotation_theta * world_to_focus;
glm::mat4 res = rotated_focus_to_camera * rotation_phi * rotation_theta * world_to_focus;
return res;
}
glm::mat4 camera_to_world(Camera& c) { return glm::inverse(world_to_camera(c)); }

View File

@@ -1,62 +0,0 @@
#include <body.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <glm/glm.hpp>
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <glm/ext/vector_float3.hpp>
#include <glm/matrix.hpp>
#include <util.hpp>
#include "camera_poses.hpp"
#define LINE_BUF_SIZE 256
#define NUM_SPHERES_PER_AXE 25
#define SPACE_PER_SPHERE 10.0f
bool parse_poses(Array<glm::mat2x3>* locs_out, const char* filepath) {
FILE* fp;
if (fopen_s(&fp, filepath, "rb")) {
printf("Error parsing %s\n", filepath);
return false;
}
char delim = ',';
char line[LINE_BUF_SIZE];
// because clang refuses to cooperate with my append implementation and generate the function code...
*locs_out = { (glm::mat2x3*)malloc(sizeof(glm::mat2x3) * 3 * NUM_SPHERES_PER_AXE * 14),
3 * NUM_SPHERES_PER_AXE * 14 };
// read in header
fgets(line, LINE_BUF_SIZE, fp);
fgets(line, LINE_BUF_SIZE, fp);
for (int camera_i = 0; !feof(fp); camera_i++) {
Array<char*> words = split_str(line, delim);
float x = atof(words[0]);
float y = atof(words[1]);
float z = atof(words[2]);
float w = atof(words[3]);
float i = atof(words[4]);
float j = atof(words[5]);
float k = atof(words[6]);
glm::mat4 pose = quat_to_mat4(glm::quat(w, i, j, k));
pose[3] = glm::vec4(x, y, z, 1);
// Generate axis spheres
for (int m = 0; m < 3; m++) {
for (int n = 0; n < NUM_SPHERES_PER_AXE; n++) {
glm::mat2x3 loc_color = glm::mat2x3(0.0);
loc_color[0][m] = n * SPACE_PER_SPHERE;
loc_color[0] = pose * glm::vec4(loc_color[0], 1);
loc_color[1] = glm::vec3(0);
loc_color[1][m] = 1.0f;
locs_out->data[camera_i*3*NUM_SPHERES_PER_AXE + m*NUM_SPHERES_PER_AXE + n] = loc_color;
}
}
fgets(line, LINE_BUF_SIZE, fp);
}
return true;
}

View File

@@ -1,36 +1,42 @@
#include <cassert>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <winnt.h>
#include <cstring>
#include <glm/ext/vector_float2.hpp>
#include <glm/ext/vector_float4.hpp>
#include <profileapi.h>
#include <synchapi.h>
#include <vector>
#include <map>
#include <set>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <glm/ext/vector_float3.hpp>
#include <glm/matrix.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <winnt.h>
#include <algorithm>
#include "glm/gtc/type_ptr.hpp"
#include "sync.hpp"
#include "util.hpp"
#include "shaders.hpp"
#include "body.hpp"
#include "camera.hpp"
#include "live_plotter.hpp"
#include "gldebug.hpp"
#define LERP_MOVE_PERIOD_S 0.05
#define STOP_WAIT_TIME_MS 500
using namespace sync;
// Constants
const char* vertex_filepath = "vertex.glsl";
const char* fragment_filepath = "fragment.glsl";
const float lerp_move_period_s = 0.05;
const int stop_wait_time_ms = 500;
const int max_point_mem = 10 << 20; // bytes
struct Point {
bool initialized;
bool replaceable;
glm::vec3 startloc;
glm::vec3 targetloc;
Body b;
@@ -44,18 +50,15 @@ static double prev_cursor_x, prev_cursor_y;
static bool mouse_pressed, scroll_pressed, stop_flag, running;
static Camera camera;
static Viewport viewport;
static Thread t;
static Mutex m;
static uint shader;
static CRITICAL_SECTION cs;
static HANDLE win_thread_h;
static DWORD win_thread_id;
static LARGE_INTEGER fr;
static pointid next_id = 0;
static std::map<uint, Point*> id_to_point; // Use a pool allocator possibly later
static std::map<Point*, uint> point_to_id;
// Constants
const char* vertex_filepath = "src/shaders/vertex.glsl";
const char* fragment_filepath = "src/shaders/fragment.glsl";
constexpr int point_buf_len
= max_point_mem / sizeof(Point); // ~max_point_mem bytes of points. does not include vertex data for obj
static Point* point_buf = (Point*)malloc(point_buf_len * sizeof(Point));
static int point_buf_i = 0;
// Private foward decls
void _resize_cb(GLFWwindow* win, int w, int h);
@@ -67,15 +70,19 @@ bool _glfw_setup();
void _refresh_win();
double _time();
DllExport bool __cdecl start(int win_w, int win_h) {
if (!InitializeCriticalSectionAndSpinCount(&cs, 0x00000400))
return false;
extern DllExport bool __cdecl start(int win_w, int win_h) {
if (running) {
printf("Already running! Call stop before calling stop again\n");
return false;
}
m = make_mutex();
for (int i = 0; i < point_buf_len; i++) {
point_buf[i].replaceable = true;
}
if (!QueryPerformanceFrequency(&fr)) {
printf("Failed to get the performance counter frequency.\n");
return false;
@@ -84,84 +91,92 @@ DllExport bool __cdecl start(int win_w, int win_h) {
glm::vec2* winsize = (glm::vec2*)malloc(sizeof(glm::vec2));
*winsize = glm::vec2(win_w, win_h);
stop_flag = false;
win_thread_h = CreateThread(NULL, 0, _win_thread, winsize, 0, &win_thread_id);
t = make_thread(_win_thread, winsize);
running = win_thread_h != NULL;
running = t != NULL;
if (!running)
printf("Error while creating the live plotter window thread.\n");
return running;
}
DllExport bool __cdecl stop() {
extern DllExport bool __cdecl stop() {
stop_flag = true;
DWORD res = WaitForSingleObject(win_thread_h, STOP_WAIT_TIME_MS);
DWORD res = WaitForSingleObject(t, stop_wait_time_ms);
bool success = res == WAIT_OBJECT_0;
running = !success; // Consider the app still running if we didn't shut down properly...?
// TODO: Please wrap away win api synch stuff. thank you
if (!running) DeleteCriticalSection(&cs);
if (!running)
dispose(m);
return success;
}
DllExport pointid __cdecl create_point(float x, float y, float z) {
EnterCriticalSection(&cs);
extern DllExport pointid __cdecl create_point(float x, float y, float z) {
lock(m);
Point* p = (Point*)malloc(sizeof(Point));
*p = {
// TODO: This system is really stupid. Please fix
// Also what happens if there isn't a replaceable point?
int slot = -1;
int start_loc = point_buf_i;
do {
if (point_buf[point_buf_i % point_buf_len].replaceable) {
slot = point_buf_i % point_buf_len;
break;
}
point_buf_i++;
} while (point_buf_i != start_loc);
assert(slot > -1);
point_buf[slot] = {
.initialized = false,
.replaceable = false,
.startloc = glm::vec3(x, y, z),
.targetloc = glm::vec3(x, y, z),
.lifetime_s = INFINITY,
.start_s = _time()
};
p->b.scale = 1.0f;
p->b.color = glm::vec4(randf() + 0.1, randf() + 0.1, randf() + 0.1, 1);
pointid id = next_id++;
id_to_point[id] = p;
point_to_id[p] = id;
LeaveCriticalSection(&cs);
return id;
point_buf[slot].b.scale = 1.0f;
point_buf[slot].b.color = glm::vec4(randf() + 0.1, randf() + 0.1, randf() + 0.1, 1);
unlock(m);
return slot;
}
DllExport void __cdecl set_color(pointid id, float r, float g, float b) {
EnterCriticalSection(&cs);
Point* p = id_to_point[id];
p->b.color = { r, g, b, p->b.color[3] };
LeaveCriticalSection(&cs);
extern DllExport void __cdecl set_color(pointid id, float r, float g, float b) {
lock(m);
Point &p = point_buf[id % point_buf_len];
p.b.color = { r, g, b, p.b.color[3] };
unlock(m);
}
DllExport void __cdecl set_scale(pointid id, float scale) {
EnterCriticalSection(&cs);
Point* p = id_to_point[id];
p->b.scale = scale;
LeaveCriticalSection(&cs);
extern DllExport void __cdecl set_scale(pointid id, float scale) {
lock(m);
Point &p = point_buf[id % point_buf_len];
p.b.scale = scale;
unlock(m);
}
DllExport void __cdecl update_point(pointid id, float x, float y, float z) {
EnterCriticalSection(&cs);
Point* p = id_to_point[id];
p->targetloc = { x, y, z };
p->startloc = p->b.pose[3];
p->start_s = _time();
LeaveCriticalSection(&cs);
extern DllExport void __cdecl update_point(pointid id, float x, float y, float z) {
lock(m);
Point &p = point_buf[id % point_buf_len];
p.targetloc = { x, y, z };
p.startloc = p.b.pose[3];
p.start_s = _time();
unlock(m);
}
DllExport void __cdecl set_lifetime(pointid id, float new_lifetime_s) {
EnterCriticalSection(&cs);
Point* p = id_to_point[id];
p->start_s = _time();
p->lifetime_s = new_lifetime_s;
LeaveCriticalSection(&cs);
extern DllExport void __cdecl set_lifetime(pointid id, float new_lifetime_s) {
lock(m);
Point &p = point_buf[id % point_buf_len];
p.start_s = _time();
p.lifetime_s = new_lifetime_s;
unlock(m);
}
DllExport void __cdecl clear_point(pointid id) {
EnterCriticalSection(&cs);
Point* p = id_to_point[id];
id_to_point.erase(id);
point_to_id.erase(p);
free(p);
LeaveCriticalSection(&cs);
extern DllExport void __cdecl clear_point(pointid id) {
lock(m);
point_buf[id % point_buf_len].replaceable = true;
unlock(m);
}
void _resize_cb(GLFWwindow* win, int w, int h) {
@@ -192,9 +207,9 @@ void _scroll_cb(GLFWwindow* win, double xoffset, double yoffset) { zoom_camera(c
DWORD _win_thread(LPVOID args) {
glm::vec2* winsize = (glm::vec2*)args;
camera = make_camera({ 0, 0, 0 }, 3000);
camera.theta = glm::radians(90.0f);
camera.phi = glm::radians(30.0f);
camera = make_camera({ 182.20, -787.72, -817.17 }, 2720);
camera.theta = 4.96;
camera.phi = 0.842;
viewport = make_viewport(winsize->x, winsize->y, 45.0f);
if (!_glfw_setup()) {
printf("Failed to initialize glfw window\n");
@@ -206,10 +221,22 @@ DWORD _win_thread(LPVOID args) {
return -1;
}
printf("Open GL Vendor: %s\n", glGetString(GL_VENDOR));
printf("Open GL Renderer: %s\n", glGetString(GL_RENDERER));
printf("Open GL Version: %s\n", glGetString(GL_VERSION));
printf("Open GL Shader Language Version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
// Enable debug messages
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(gl_debug_cb, 0);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
if (!load_shader(&shader, vertex_filepath, fragment_filepath)) {
printf("Failed to compile shaders\n");
return -1;
}
use_shader(shader);
// This swapping bit is probably unnecessary now that I clear in the loop.
// I was getting a flashing issue during the tutorial...
@@ -230,9 +257,11 @@ DWORD _win_thread(LPVOID args) {
bool _glfw_setup() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
win = glfwCreateWindow(viewport.width, viewport.height, "LivePlotter", NULL, NULL);
if (win == NULL) {
printf("Failed to create GLFW window\n");
@@ -254,29 +283,32 @@ void _refresh_win() {
set_uniform(shader, "camera_t", world_to_camera(camera));
set_uniform(shader, "projection_t", camera_to_projection(viewport));
if (TryEnterCriticalSection(&cs)) {
for (const auto& [id, p] : id_to_point) {
if (trylock(m)) {
for (int i = 0; i < point_buf_len; i++) {
Point &p = point_buf[i];
if (p.replaceable) continue;
// Initialize if not done so yet
if (!p->initialized) {
create_new_sphere(&p->b, p->b.scale);
p->b.shader = shader;
p->b.pose = glm::translate(glm::mat4(1), p->startloc);
p->initialized = true;
if (!p.initialized) {
create_new_sphere(&p.b, p.b.scale, p.b.color);
p.b.shader = shader;
p.b.pose = glm::translate(glm::mat4(1), p.startloc);
p.initialized = true;
}
// Perform fade
double elapsed_time_s = _time() - p->start_s;
float t = elapsed_time_s / p->lifetime_s;
t = std::clamp(t, 0.0f, 1.0f);
p->b.color.w = lerp(1.0, 0.0, t);
double elapsed_time_s = _time() - p.start_s;
float t = elapsed_time_s / p.lifetime_s;
t = glm::clamp(t, 0.0f, 1.0f);
p.b.color.w = lerp(1.0, 0.0, t);
// Lerp position
t = elapsed_time_s / LERP_MOVE_PERIOD_S;
t = std::clamp(t, 0.0f, 1.0f);
p->b.pose[3] = glm::vec4(lerp(p->startloc, p->targetloc, t), 1);
draw_body(p->b);
t = elapsed_time_s / lerp_move_period_s;
t = glm::clamp(t, 0.0f, 1.0f);
p.b.pose[3] = glm::vec4(lerp(p.startloc, p.targetloc, t), 1);
draw_body(p.b);
}
LeaveCriticalSection(&cs);
unlock(m);
}
glfwSwapBuffers(win);
glfwPollEvents();
@@ -290,4 +322,3 @@ double _time() {
}
return (double)timeticks.QuadPart / (double)fr.QuadPart;
}

View File

@@ -1,46 +0,0 @@
//#include <iostream>
//#include <string>
//#include <map>
//
//#include "camera_poses.hpp"
//#include "live_plotter.hpp"
//
//static std::map<std::string, pointid> name_to_id;
//
//int main() {
// Array<glm::mat2x3> camera_pose_axes = { NULL, 0 };
// if (!parse_poses(&camera_pose_axes, "poses.csv")) {
// return -1;
// }
//
// start(800, 800);
//
// for (int i = 0; i < camera_pose_axes.len; i++) {
// glm::vec3 p = camera_pose_axes[i][0];
// glm::vec3 color = camera_pose_axes[i][1];
// pointid id = create_point(p.x, p.y, p.z);
// set_color(id, color.x, color.y, color.z);
// set_scale(id, 10);
// }
//
// while (true) {
// std::string line;
// std::getline(std::cin, line);
// Array<char*> words = split_str(line.c_str());
// if (!words.len == 4)
// return NULL;
// printf("Received: %s, %s, %s, %s\n", words[0], words[1], words[2], words[3]); // echo for debugging
// std::string name = std::string(words[0]);
// float x = atof(words[1]);
// float y = atof(words[2]);
// float z = atof(words[3]);
//
// if (auto it = name_to_id.find(name); it != name_to_id.end()) {
// update_point(it->second, x, y, z);
// } else {
// name_to_id[name] = create_point(x, y, z);
// set_lifetime(name_to_id[name], 0.2);
// set_scale(name_to_id[name], 15);
// }
// }
//}

View File

@@ -68,24 +68,24 @@ void set_uniform(uint id, const char* name, uniform_variant value) {
}
bool _compile_shader(uint *out_id, const char* filepath, int shader_type) {
Array<char> source;
std::string source;
if (!read_file(&source, filepath))
return false;
uint id = glCreateShader(shader_type);
glShaderSource(id, 1, &source.data, (int*)&source.len);
int sz = source.size();
const char* data = source.c_str();
glShaderSource(id, 1, &data, &sz);
glCompileShader(id);
free(source.data);
int status;
glGetShaderiv(id, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
char err_msg[MAX_ERR_MSG_LEN];
glGetShaderInfoLog(id, MAX_ERR_MSG_LEN, NULL, err_msg);
printf("Error compiling shader %s\n", filepath);
printf("%.*s\n", (int)source.len, source.data);
printf("Error msg: %s\n", err_msg);
return false;
}
*out_id = id;
return status == GL_TRUE;

View File

@@ -1,94 +1,22 @@
#include <cstdio>
#include <assert.h>
#include <cstring>
#include <cwctype>
#include <stdlib.h>
#include <glm/ext/quaternion_float.hpp>
#include <glm/mat4x4.hpp>
#include "util.hpp"
#include "body.hpp"
Array<char*> _split_str_inner(const char* s, char delim, bool just_check_ws);
using namespace std;
template<class T> void append(Array<T>& a, T el) {
if (a.len == a.cap) {
resize(a, std::max((size_t)8, a.cap * 2));
}
a[a.len] = el;
a.len++;
}
template<class T> T pop(Array<T>& a) {
assert(a.len >= 1);
a.len--;
return a.data[a.len + 1];
}
template<class T> void resize(Array<T>& a, size_t new_cap) {
T* new_data = (T*)malloc(sizeof(T) * new_cap);
if (a.len > 0) {
memcpy(new_data, a.data, std::min(a.len, new_cap));
}
free(a.data);
a.data = new_data;
a.len = std::min(a.len, new_cap);
a.cap = new_cap;
}
template<class T> void clear(Array<T>& a) {
a.len = 0;
}
bool read_file(Array<char>* out, const char* filepath) {
FILE* fp = NULL;
if (fopen_s(&fp, filepath, "rb") != 0) {
printf("ERROR Failed to open file %s\n", filepath);
bool read_file(string* s, const char* filepath) {
ifstream file(filepath);
if (!file.is_open()) {
return false;
}
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp);
fseek(fp, 0, SEEK_SET);
char* data = (char*)malloc(sizeof(char) * sz);
fread(data, sizeof(char), sz, fp);
fclose(fp);
out->data = data;
out->len = sz;
*s = { istreambuf_iterator<char>(file), istreambuf_iterator<char>() };
return true;
}
Array<char*> split_str(const char* s, char delimiter) { return _split_str_inner(s, delimiter, false); }
Array<char*> split_str(const char* s) { return _split_str_inner(s, ' ', true); }
Array<char*> _split_str_inner(const char* s, char delim, bool just_check_ws) {
Array<char*> res = { NULL, 0, 0 };
char c;
int i = 0;
Array<char> cur_word = { NULL, 0, 0 };
while (true) {
c = s[i++];
bool is_delim = just_check_ws ? iswspace(c) : c == delim;
if ((is_delim || c == '\0') && cur_word.len > 0) {
char* word = (char*)malloc(sizeof(char) * cur_word.len + 1);
memcpy(word, cur_word.data, cur_word.len);
word[cur_word.len] = '\0';
append(res, word);
clear(cur_word);
if (c == '\0') {
break;
}
continue;
} else {
append(cur_word, c);
}
if (c == '\0') {
break;
}
vector<string> split_str(string s, char delim) {
vector<string> res;
string cur_word;
istringstream ss(s);
while (getline(ss, cur_word, delim)) {
res.push_back(cur_word);
}
return res;
}
@@ -109,6 +37,4 @@ glm::mat4 quat_to_mat4(glm::quat q) {
return glm::mat4(col0, col1, col2, col3);
}
float randf() {
return (float)rand() / (float)RAND_MAX;
}
float randf() { return (float)abs(rand()) / (float)RAND_MAX; }

View File

@@ -1,22 +0,0 @@
import numpy as np
import subprocess
from pathlib import Path
import time
p = subprocess.Popen(Path("bin", "x64", "Debug", "LivePlotter.exe"), stdin=subprocess.PIPE)
lines = None
with open("gpoints_rotate.obj", "r") as f:
lines = f.readlines()
period = 0.01
for i in range(len(lines)):
time.sleep(period)
words = lines[i].split()
x = words[1]
y = words[2]
z = words[3]
name = "".join(words[4:])
p.stdin.write(f"{name} {x} {y} {z}\n".encode("utf8"))
p.stdin.flush()