pax_global_header00006660000000000000000000000064135127525610014521gustar00rootroot0000000000000052 comment=6c7291b919a9128518c682a706fb53399feb6f81 leocad-19.07.1/000077500000000000000000000000001351275256100131275ustar00rootroot00000000000000leocad-19.07.1/.gitattributes000066400000000000000000000004771351275256100160320ustar00rootroot00000000000000# Set the default behavior, in case people don't have core.autocrlf set. * text=auto # Explicitly declare text files you want to always be normalized and converted # to native line endings on checkout. *.cpp text *.h text # Denote all files that are truly binary and should not be modified. *.png binary *.jpg binary leocad-19.07.1/.gitignore000066400000000000000000000004621351275256100151210ustar00rootroot00000000000000*.suo *.sln *.vcxproj *.filters *.user *.pdb *.db *.psess *.opendb *.opensdf *.sdf *.suo *.vspx *.xcodeproj *.qm *.ldr *.dat *.mpd !/resources/*.ldr *.dae *.3ds *.obj build debug release ipch Debug* .DS_Store .qmake.stash Makefile library.bin leocad_plugin_import.cpp uic_wrapper.bat /tools/setup/*.exe leocad-19.07.1/.travis.yml000066400000000000000000000065551351275256100152530ustar00rootroot00000000000000language: cpp matrix: include: - os: linux dist: trusty addons: apt: sources: - sourceline: "ppa:beineri/opt-qt487-trusty" packages: - opt-qt4-qmake opt-qt4-dev-tools opt-libqt4-dev opt-libqt4-dev-bin opt-libqt4-opengl-dev sudo: required compiler: gcc env: - QT_BASE=48 - os: linux dist: trusty addons: apt: sources: - sourceline: "ppa:beineri/opt-qt-5.10.1-trusty" packages: - qt510base sudo: required compiler: gcc env: - QT_BASE=510 - os: osx compiler: clang env: - QT_BASE=57 before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt5 grep; brew link --force qt5; wget https://github.com/leozide/leocad/releases/download/v18.02/Library-Linux-11494.zip -O library.zip; unzip library.zip; fi script: - | if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then source /opt/qt*/bin/qt*-env.sh qmake PREFIX=/usr -v qmake PREFIX=/usr -r make -j$(nproc); export COMPILE_RESULT=$? if [[ "$QT_BASE" != "510" ]]; then exit $COMPILE_RESULT; fi make install INSTALL_ROOT=AppDir if [[ "$TRAVIS_TAG" != "" ]]; then wget https://github.com/leozide/leocad/releases/download/v18.02/Library-Linux-11494.zip -O library.zip; unzip library.zip; mkdir -p AppDir/usr/share/leocad; mv library.bin AppDir/usr/share/leocad/library.bin; fi wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" chmod a+x linuxdeployqt*.AppImage unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH export VERSION=$(git rev-parse --short HEAD) ./linuxdeployqt*.AppImage ./AppDir/usr/share/applications/*.desktop -bundle-non-qt-libs ./linuxdeployqt*.AppImage --appimage-extract export PATH=$(readlink -f ./squashfs-root/usr/bin/):$PATH ./squashfs-root/usr/bin/appimagetool AppDir/ mv ./LeoCAD-$VERSION-x86_64.AppImage ./LeoCAD-Linux-$VERSION-x86_64.AppImage elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then qmake PREFIX=/usr -v qmake PREFIX=/usr -r make -j$(sysctl -n hw.ncpu) cd build/release macdeployqt LeoCAD.app -dmg mv LeoCAD.dmg LeoCAD-macOS-$(git rev-parse --short HEAD).dmg fi after_success: - | export GREP_PATH=grep; if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export GREP_PATH=ggrep; fi curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/leozide/leocad/commits/master -o repo.txt; export REMOTE=$($GREP_PATH -Po '(?<=: \")(([a-z0-9])\w+)(?=\")' -m 1 repo.txt); export LOCAL=$(git rev-parse HEAD); if [[ "$REMOTE" != "$LOCAL" ]]; then echo "Build no longer current. $REMOTE vs $LOCAL - aborting upload."; exit 0; fi; if [[ "$QT_BASE" = "510" && "$TRAVIS_OS_NAME" = "linux" ]]; then wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh bash upload.sh LeoCAD*.AppImage* elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh bash upload.sh LeoCAD*.dmg* fi branches: except: - # Do not build tags that we create when we upload to GitHub Releases - /^(?i:continuous)/ leocad-19.07.1/PKGBUILD000066400000000000000000000037001351275256100142530ustar00rootroot00000000000000# Maintainer: Peter Bartfai pkgname=leocad pkgver=18.02 pkgrel=1 pkgdesc="LeoCAD is a CAD program for creating virtual LEGO models." url="http://leocad.org" arch=('x86_64' 'i686') license=('GPL') #Qt4.x depends=('qt4' 'libpng' 'libjpeg-turbo' 'mesa-libgl') #Qt5.x #depends=('qt5-base' 'qt5-tools' 'qt5-gamepad' 'libpng' 'libjpeg-turbo' 'mesa-libgl') makedepends=('glu' 'ca-certificates') conflicts=() replaces=() backup=() source=("leocad-git.tar.gz") md5sums=(SKIP) build() { cd ${srcdir}/leocad-git if test "$CARCH" == x86_64; then PLATFORM=linux-g++-64 else PLATFORM=linux-g++-32 fi if [ -x /usr/bin/qmake ] ; then qmake -spec $PLATFORM DISABLE_UPDATE_CHECK=1 LDRAW_LIBRARY_PATH=/usr/share/ldraw ; lrelease leocad.pro ; elif [ -x /usr/bin/qmake-qt4 ] ; then qmake-qt4 -spec $PLATFORM DISABLE_UPDATE_CHECK=1 LDRAW_LIBRARY_PATH=/usr/share/ldraw ; lrelease-qt4 leocad.pro ; elif [ -x /usr/bin/qmake-qt5 ] ; then qmake-qt5 -spec $PLATFORM DISABLE_UPDATE_CHECK=1 LDRAW_LIBRARY_PATH=/usr/share/ldraw ; lrelease-qt5 leocad.pro ; fi make } package() { cd "${srcdir}/leocad-git" mkdir -p ${pkgdir}/usr/bin mkdir -p ${pkgdir}/usr/share/leocad install -m 755 build/release/leocad ${pkgdir}/usr/bin install -m 644 docs/README.txt ${pkgdir}/usr/share/leocad/README.txt install -m 644 docs/CREDITS.txt ${pkgdir}/usr/share/leocad/CREDITS.txt install -m 644 docs/COPYING.txt ${pkgdir}/usr/share/leocad/COPYING.txt mkdir -p ${pkgdir}/usr/share/mime/packages/ mkdir -p ${pkgdir}/usr/share/applications/ mkdir -p ${pkgdir}/usr/share/icons/hicolor/scalable/mimetypes install -m 644 qt/leocad.xml \ ${pkgdir}/usr/share/mime/packages/leocad.xml install -m 644 qt/leocad.desktop \ ${pkgdir}/usr/share/applications/leocad.desktop install -m 644 resources/application-vnd.leocad.svg \ ${pkgdir}/usr/share/icons/hicolor/scalable/mimetypes/application-vnd.leocad.svg make INSTALL_ROOT="${pkgdir}" install } leocad-19.07.1/common/000077500000000000000000000000001351275256100144175ustar00rootroot00000000000000leocad-19.07.1/common/camera.cpp000066400000000000000000000741611351275256100163640ustar00rootroot00000000000000#include "lc_global.h" #include "lc_math.h" #include "lc_colors.h" #include #include #include #include #include "lc_file.h" #include "camera.h" #include "lc_application.h" #include "lc_context.h" #define LC_CAMERA_POSITION_EDGE 7.5f #define LC_CAMERA_TARGET_EDGE 7.5f #define LC_CAMERA_SAVE_VERSION 7 // LeoCAD 0.80 lcCamera::lcCamera(bool Simple) : lcObject(LC_OBJECT_CAMERA) { Initialize(); if (Simple) mState |= LC_CAMERA_SIMPLE; else { mPosition = lcVector3(-250.0f, -250.0f, 75.0f); mTargetPosition = lcVector3(0.0f, 0.0f, 0.0f); mUpVector = lcVector3(-0.2357f, -0.2357f, 0.94281f); ChangeKey(mPositionKeys, mPosition, 1, true); ChangeKey(mTargetPositionKeys, mTargetPosition, 1, true); ChangeKey(mUpVectorKeys, mUpVector, 1, true); UpdatePosition(1); } } lcCamera::lcCamera(float ex, float ey, float ez, float tx, float ty, float tz) : lcObject(LC_OBJECT_CAMERA) { // Fix the up vector lcVector3 UpVector(0, 0, 1), FrontVector(ex - tx, ey - ty, ez - tz), SideVector; FrontVector.Normalize(); if (FrontVector == UpVector) SideVector = lcVector3(1, 0, 0); else SideVector = lcCross(FrontVector, UpVector); UpVector = lcCross(SideVector, FrontVector); UpVector.Normalize(); Initialize(); ChangeKey(mPositionKeys, lcVector3(ex, ey, ez), 1, true); ChangeKey(mTargetPositionKeys, lcVector3(tx, ty, tz), 1, true); ChangeKey(mUpVectorKeys, UpVector, 1, true); UpdatePosition(1); } lcCamera::~lcCamera() { } void lcCamera::Initialize() { m_fovy = 30.0f; m_zNear = 25.0f; m_zFar = 50000.0f; mState = 0; memset(m_strName, 0, sizeof(m_strName)); } void lcCamera::CreateName(const lcArray& Cameras) { if (m_strName[0]) { bool Found = false; for (int CameraIdx = 0; CameraIdx < Cameras.GetSize(); CameraIdx++) { if (!strcmp(Cameras[CameraIdx]->m_strName, m_strName)) { Found = true; break; } } if (!Found) return; } int i, max = 0; const char* Prefix = "Camera "; for (int CameraIdx = 0; CameraIdx < Cameras.GetSize(); CameraIdx++) if (strncmp(Cameras[CameraIdx]->m_strName, Prefix, strlen(Prefix)) == 0) if (sscanf(Cameras[CameraIdx]->m_strName + strlen(Prefix), " %d", &i) == 1) if (i > max) max = i; sprintf(m_strName, "%s %d", Prefix, max+1); } void lcCamera::SaveLDraw(QTextStream& Stream) const { QLatin1String LineEnding("\r\n"); Stream << QLatin1String("0 !LEOCAD CAMERA FOV ") << m_fovy << QLatin1String(" ZNEAR ") << m_zNear << QLatin1String(" ZFAR ") << m_zFar << LineEnding; if (mPositionKeys.GetSize() > 1) SaveKeysLDraw(Stream, mPositionKeys, "CAMERA POSITION_KEY "); else Stream << QLatin1String("0 !LEOCAD CAMERA POSITION ") << mPosition[0] << ' ' << mPosition[1] << ' ' << mPosition[2] << LineEnding; if (mTargetPositionKeys.GetSize() > 1) SaveKeysLDraw(Stream, mTargetPositionKeys, "CAMERA TARGET_POSITION_KEY "); else Stream << QLatin1String("0 !LEOCAD CAMERA TARGET_POSITION ") << mTargetPosition[0] << ' ' << mTargetPosition[1] << ' ' << mTargetPosition[2] << LineEnding; if (mUpVectorKeys.GetSize() > 1) SaveKeysLDraw(Stream, mUpVectorKeys, "CAMERA UP_VECTOR_KEY "); else Stream << QLatin1String("0 !LEOCAD CAMERA UP_VECTOR ") << mUpVector[0] << ' ' << mUpVector[1] << ' ' << mUpVector[2] << LineEnding; Stream << QLatin1String("0 !LEOCAD CAMERA "); if (IsHidden()) Stream << QLatin1String("HIDDEN"); if (IsOrtho()) Stream << QLatin1String("ORTHOGRAPHIC "); Stream << QLatin1String("NAME ") << m_strName << LineEnding; } bool lcCamera::ParseLDrawLine(QTextStream& Stream) { while (!Stream.atEnd()) { QString Token; Stream >> Token; if (Token == QLatin1String("HIDDEN")) SetHidden(true); else if (Token == QLatin1String("ORTHOGRAPHIC")) SetOrtho(true); else if (Token == QLatin1String("FOV")) Stream >> m_fovy; else if (Token == QLatin1String("ZNEAR")) Stream >> m_zNear; else if (Token == QLatin1String("ZFAR")) Stream >> m_zFar; else if (Token == QLatin1String("POSITION")) { Stream >> mPosition[0] >> mPosition[1] >> mPosition[2]; ChangeKey(mPositionKeys, mPosition, 1, true); } else if (Token == QLatin1String("TARGET_POSITION")) { Stream >> mTargetPosition[0] >> mTargetPosition[1] >> mTargetPosition[2]; ChangeKey(mTargetPositionKeys, mTargetPosition, 1, true); } else if (Token == QLatin1String("UP_VECTOR")) { Stream >> mUpVector[0] >> mUpVector[1] >> mUpVector[2]; ChangeKey(mUpVectorKeys, mUpVector, 1, true); } else if (Token == QLatin1String("POSITION_KEY")) LoadKeysLDraw(Stream, mPositionKeys); else if (Token == QLatin1String("TARGET_POSITION_KEY")) LoadKeysLDraw(Stream, mTargetPositionKeys); else if (Token == QLatin1String("UP_VECTOR_KEY")) LoadKeysLDraw(Stream, mUpVectorKeys); else if (Token == QLatin1String("NAME")) { QString Name = Stream.readAll().trimmed(); QByteArray NameUtf = Name.toUtf8(); // todo: replace with qstring strncpy(m_strName, NameUtf.constData(), sizeof(m_strName)); m_strName[sizeof(m_strName) - 1] = 0; return true; } } return false; } ///////////////////////////////////////////////////////////////////////////// // Camera save/load bool lcCamera::FileLoad(lcFile& file) { quint8 version, ch; version = file.ReadU8(); if (version > LC_CAMERA_SAVE_VERSION) return false; if (version > 5) { if (file.ReadU8() != 1) return false; quint16 time; float param[4]; quint8 type; quint32 n; file.ReadU32(&n, 1); while (n--) { file.ReadU16(&time, 1); file.ReadFloats(param, 4); file.ReadU8(&type, 1); if (type == 0) ChangeKey(mPositionKeys, lcVector3(param[0], param[1], param[2]), time, true); else if (type == 1) ChangeKey(mTargetPositionKeys, lcVector3(param[0], param[1], param[2]), time, true); else if (type == 2) ChangeKey(mUpVectorKeys, lcVector3(param[0], param[1], param[2]), time, true); } file.ReadU32(&n, 1); while (n--) { file.ReadU16(&time, 1); file.ReadFloats(param, 4); file.ReadU8(&type, 1); } } if (version == 4) { file.ReadBuffer(m_strName, 80); m_strName[80] = 0; } else { ch = file.ReadU8(); if (ch == 0xFF) return false; // don't read CString file.ReadBuffer(m_strName, ch); m_strName[ch] = 0; } if (version < 3) { double d[3]; float f[3]; file.ReadDoubles(d, 3); f[0] = (float)d[0]; f[1] = (float)d[1]; f[2] = (float)d[2]; ChangeKey(mPositionKeys, lcVector3(f[0], f[1], f[2]), 1, true); file.ReadDoubles(d, 3); f[0] = (float)d[0]; f[1] = (float)d[1]; f[2] = (float)d[2]; ChangeKey(mTargetPositionKeys, lcVector3(f[0], f[1], f[2]), 1, true); file.ReadDoubles(d, 3); f[0] = (float)d[0]; f[1] = (float)d[1]; f[2] = (float)d[2]; ChangeKey(mUpVectorKeys, lcVector3(f[0], f[1], f[2]), 1, true); } if (version == 3) { ch = file.ReadU8(); while (ch--) { quint8 step; double eye[3], target[3], up[3]; float f[3]; file.ReadDoubles(eye, 3); file.ReadDoubles(target, 3); file.ReadDoubles(up, 3); file.ReadU8(&step, 1); if (up[0] == 0 && up[1] == 0 && up[2] == 0) up[2] = 1; f[0] = (float)eye[0]; f[1] = (float)eye[1]; f[2] = (float)eye[2]; ChangeKey(mPositionKeys, lcVector3(f[0], f[1], f[2]), step, true); f[0] = (float)target[0]; f[1] = (float)target[1]; f[2] = (float)target[2]; ChangeKey(mTargetPositionKeys, lcVector3(f[0], f[1], f[2]), step, true); f[0] = (float)up[0]; f[1] = (float)up[1]; f[2] = (float)up[2]; ChangeKey(mUpVectorKeys, lcVector3(f[0], f[1], f[2]), step, true); file.ReadS32(); // snapshot file.ReadS32(); // cam } } if (version < 4) { m_fovy = (float)file.ReadDouble(); m_zFar = (float)file.ReadDouble(); m_zNear= (float)file.ReadDouble(); } else { qint32 n; if (version < 6) { quint16 time; float param[4]; quint8 type; n = file.ReadS32(); while (n--) { file.ReadU16(&time, 1); file.ReadFloats(param, 3); file.ReadU8(&type, 1); if (type == 0) ChangeKey(mPositionKeys, lcVector3(param[0], param[1], param[2]), time, true); else if (type == 1) ChangeKey(mTargetPositionKeys, lcVector3(param[0], param[1], param[2]), time, true); else if (type == 2) ChangeKey(mUpVectorKeys, lcVector3(param[0], param[1], param[2]), time, true); } n = file.ReadS32(); while (n--) { file.ReadU16(&time, 1); file.ReadFloats(param, 3); file.ReadU8(&type, 1); } } file.ReadFloats(&m_fovy, 1); file.ReadFloats(&m_zFar, 1); file.ReadFloats(&m_zNear, 1); if (version < 5) { n = file.ReadS32(); if (n != 0) mState |= LC_CAMERA_HIDDEN; } else { ch = file.ReadU8(); if (ch & 1) mState |= LC_CAMERA_HIDDEN; file.ReadU8(); } } if ((version > 1) && (version < 4)) { quint32 show; qint32 user; file.ReadU32(&show, 1); // if (version > 2) file.ReadS32(&user, 1); if (show == 0) mState |= LC_CAMERA_HIDDEN; } if (version < 7) { m_zFar *= 25.0f; m_zNear *= 25.0f; for (int KeyIdx = 0; KeyIdx < mPositionKeys.GetSize(); KeyIdx++) mPositionKeys[KeyIdx].Value *= 25.0f; for (int KeyIdx = 0; KeyIdx < mTargetPositionKeys.GetSize(); KeyIdx++) mTargetPositionKeys[KeyIdx].Value *= 25.0f; } return true; } void lcCamera::CompareBoundingBox(lcVector3& Min, lcVector3& Max) { const lcVector3 Points[2] = { mPosition, mTargetPosition }; for (int i = 0; i < 2; i++) { const lcVector3& Point = Points[i]; // TODO: this should check the entire mesh Min = lcMin(Point, Min); Max = lcMax(Point, Max); } } void lcCamera::MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance) { if (IsSimple()) AddKey = false; if (IsSelected(LC_CAMERA_SECTION_POSITION)) { mPosition += Distance; ChangeKey(mPositionKeys, mPosition, Step, AddKey); } if (IsSelected(LC_CAMERA_SECTION_TARGET)) { mTargetPosition += Distance; ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey); } else if (IsSelected(LC_CAMERA_SECTION_UPVECTOR)) { mUpVector += Distance; mUpVector.Normalize(); ChangeKey(mUpVectorKeys, mUpVector, Step, AddKey); } lcVector3 FrontVector(mTargetPosition - mPosition); lcVector3 SideVector = lcCross(FrontVector, mUpVector); if (fabsf(lcDot(mUpVector, SideVector)) > 0.99f) SideVector = lcVector3(1, 0, 0); mUpVector = lcCross(SideVector, FrontVector); mUpVector.Normalize(); } void lcCamera::MoveRelative(const lcVector3& Distance, lcStep Step, bool AddKey) { if (IsSimple()) AddKey = false; lcVector3 Relative = lcMul30(Distance, lcMatrix44Transpose(mWorldView)) * 5.0f; mPosition += Relative; ChangeKey(mPositionKeys, mPosition, Step, AddKey); mTargetPosition += Relative; ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey); UpdatePosition(Step); } void lcCamera::UpdatePosition(lcStep Step) { if (!IsSimple()) { mPosition = CalculateKey(mPositionKeys, Step); mTargetPosition = CalculateKey(mTargetPositionKeys, Step); mUpVector = CalculateKey(mUpVectorKeys, Step); } lcVector3 FrontVector(mPosition - mTargetPosition); lcVector3 SideVector = lcCross(FrontVector, mUpVector); mUpVector = lcNormalize(lcCross(SideVector, FrontVector)); mWorldView = lcMatrix44LookAt(mPosition, mTargetPosition, mUpVector); } void lcCamera::CopyPosition(const lcCamera* camera) { m_fovy = camera->m_fovy; m_zNear = camera->m_zNear; m_zFar = camera->m_zFar; mWorldView = camera->mWorldView; mPosition = camera->mPosition; mTargetPosition = camera->mTargetPosition; mUpVector = camera->mUpVector; mState |= (camera->mState&LC_CAMERA_ORTHO); } void lcCamera::DrawInterface(lcContext* Context, const lcScene& Scene) const { Q_UNUSED(Scene); Context->SetMaterial(LC_MATERIAL_UNLIT_COLOR); lcMatrix44 ViewWorldMatrix = lcMatrix44AffineInverse(mWorldView); ViewWorldMatrix.SetTranslation(lcVector3(0, 0, 0)); lcMatrix44 CameraViewMatrix = lcMul(ViewWorldMatrix, lcMatrix44Translation(mPosition)); Context->SetWorldMatrix(CameraViewMatrix); float Verts[(12 + 8 + 8 + 3 + 4) * 3]; float* CurVert = Verts; float Length = lcLength(mPosition - mTargetPosition); *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE * 2; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE * 2; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE * 2; *CurVert++ = LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE; *CurVert++ = -LC_CAMERA_POSITION_EDGE * 2; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE - Length; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE - Length; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE - Length; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE - Length; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE - Length; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE - Length; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE - Length; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE - Length; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE + 25.0f; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE + 25.0f; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE + 25.0f; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE + 25.0f; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE + 25.0f; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE + 25.0f; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE + 25.0f; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = LC_CAMERA_TARGET_EDGE; *CurVert++ = -LC_CAMERA_TARGET_EDGE + 25.0f; *CurVert++ = -LC_CAMERA_TARGET_EDGE; *CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = -Length; *CurVert++ = 0.0f; *CurVert++ = 25.0f; *CurVert++ = 0.0f; const GLushort Indices[40 + 24 + 24 + 4 + 16] = { 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7, 8, 9, 9, 10, 10, 11, 11, 8, 8, 28, 9, 28, 10, 28, 11, 28, 12, 13, 13, 14, 14, 15, 15, 12, 16, 17, 17, 18, 18, 19, 19, 16, 12, 16, 13, 17, 14, 18, 15, 19, 20, 21, 21, 22, 22, 23, 23, 20, 24, 25, 25, 26, 26, 27, 27, 24, 20, 24, 21, 25, 22, 26, 23, 27, 28, 29, 28, 30, 31, 32, 32, 33, 33, 34, 34, 31, 28, 31, 28, 32, 28, 33, 28, 34 }; Context->SetVertexBufferPointer(Verts); Context->SetVertexFormatPosition(3); Context->SetIndexBufferPointer(Indices); float LineWidth = lcGetPreferences().mLineWidth; if (!IsSelected()) { Context->SetLineWidth(LineWidth); Context->SetInterfaceColor(LC_COLOR_CAMERA); Context->DrawIndexedPrimitives(GL_LINES, 40 + 24 + 24 + 4, GL_UNSIGNED_SHORT, 0); } else { if (IsSelected(LC_CAMERA_SECTION_POSITION)) { Context->SetLineWidth(2.0f * LineWidth); if (IsFocused(LC_CAMERA_SECTION_POSITION)) Context->SetInterfaceColor(LC_COLOR_FOCUSED); else Context->SetInterfaceColor(LC_COLOR_SELECTED); } else { Context->SetLineWidth(LineWidth); Context->SetInterfaceColor(LC_COLOR_CAMERA); } Context->DrawIndexedPrimitives(GL_LINES, 40, GL_UNSIGNED_SHORT, 0); if (IsSelected(LC_CAMERA_SECTION_TARGET)) { Context->SetLineWidth(2.0f * LineWidth); if (IsFocused(LC_CAMERA_SECTION_TARGET)) Context->SetInterfaceColor(LC_COLOR_FOCUSED); else Context->SetInterfaceColor(LC_COLOR_SELECTED); } else { Context->SetLineWidth(LineWidth); Context->SetInterfaceColor(LC_COLOR_CAMERA); } Context->DrawIndexedPrimitives(GL_LINES, 24, GL_UNSIGNED_SHORT, 40 * 2); if (IsSelected(LC_CAMERA_SECTION_UPVECTOR)) { Context->SetLineWidth(2.0f * LineWidth); if (IsFocused(LC_CAMERA_SECTION_UPVECTOR)) Context->SetInterfaceColor(LC_COLOR_FOCUSED); else Context->SetInterfaceColor(LC_COLOR_SELECTED); } else { Context->SetLineWidth(LineWidth); Context->SetInterfaceColor(LC_COLOR_CAMERA); } Context->DrawIndexedPrimitives(GL_LINES, 24, GL_UNSIGNED_SHORT, (40 + 24) * 2); Context->SetInterfaceColor(LC_COLOR_CAMERA); Context->SetLineWidth(LineWidth); float SizeY = tanf(LC_DTOR * m_fovy / 2) * Length; float SizeX = SizeY * 1.333f; *CurVert++ = SizeX; *CurVert++ = SizeY; *CurVert++ = -Length; *CurVert++ = -SizeX; *CurVert++ = SizeY; *CurVert++ = -Length; *CurVert++ = -SizeX; *CurVert++ = -SizeY; *CurVert++ = -Length; *CurVert++ = SizeX; *CurVert++ = -SizeY; *CurVert++ = -Length; Context->DrawIndexedPrimitives(GL_LINES, 4 + 16, GL_UNSIGNED_SHORT, (40 + 24 + 24) * 2); } } void lcCamera::RemoveKeyFrames() { mPositionKeys.RemoveAll(); ChangeKey(mPositionKeys, mPosition, 1, true); mTargetPositionKeys.RemoveAll(); ChangeKey(mTargetPositionKeys, mTargetPosition, 1, true); mUpVectorKeys.RemoveAll(); ChangeKey(mUpVectorKeys, mUpVector, 1, true); } void lcCamera::RayTest(lcObjectRayTest& ObjectRayTest) const { lcVector3 Min = lcVector3(-LC_CAMERA_POSITION_EDGE, -LC_CAMERA_POSITION_EDGE, -LC_CAMERA_POSITION_EDGE); lcVector3 Max = lcVector3(LC_CAMERA_POSITION_EDGE, LC_CAMERA_POSITION_EDGE, LC_CAMERA_POSITION_EDGE); lcVector3 Start = lcMul31(ObjectRayTest.Start, mWorldView); lcVector3 End = lcMul31(ObjectRayTest.End, mWorldView); float Distance; if (lcBoundingBoxRayIntersectDistance(Min, Max, Start, End, &Distance, nullptr) && (Distance < ObjectRayTest.Distance)) { ObjectRayTest.ObjectSection.Object = const_cast(this); ObjectRayTest.ObjectSection.Section = LC_CAMERA_SECTION_POSITION; ObjectRayTest.Distance = Distance; } Min = lcVector3(-LC_CAMERA_TARGET_EDGE, -LC_CAMERA_TARGET_EDGE, -LC_CAMERA_TARGET_EDGE); Max = lcVector3(LC_CAMERA_TARGET_EDGE, LC_CAMERA_TARGET_EDGE, LC_CAMERA_TARGET_EDGE); lcMatrix44 WorldView = mWorldView; WorldView.SetTranslation(lcMul30(-mTargetPosition, WorldView)); Start = lcMul31(ObjectRayTest.Start, WorldView); End = lcMul31(ObjectRayTest.End, WorldView); if (lcBoundingBoxRayIntersectDistance(Min, Max, Start, End, &Distance, nullptr) && (Distance < ObjectRayTest.Distance)) { ObjectRayTest.ObjectSection.Object = const_cast(this); ObjectRayTest.ObjectSection.Section = LC_CAMERA_SECTION_TARGET; ObjectRayTest.Distance = Distance; } lcMatrix44 ViewWorld = lcMatrix44AffineInverse(mWorldView); lcVector3 UpVectorPosition = lcMul31(lcVector3(0, 25, 0), ViewWorld); WorldView = mWorldView; WorldView.SetTranslation(lcMul30(-UpVectorPosition, WorldView)); Start = lcMul31(ObjectRayTest.Start, WorldView); End = lcMul31(ObjectRayTest.End, WorldView); if (lcBoundingBoxRayIntersectDistance(Min, Max, Start, End, &Distance, nullptr) && (Distance < ObjectRayTest.Distance)) { ObjectRayTest.ObjectSection.Object = const_cast(this); ObjectRayTest.ObjectSection.Section = LC_CAMERA_SECTION_UPVECTOR; ObjectRayTest.Distance = Distance; } } void lcCamera::BoxTest(lcObjectBoxTest& ObjectBoxTest) const { lcVector3 Min(-LC_CAMERA_POSITION_EDGE, -LC_CAMERA_POSITION_EDGE, -LC_CAMERA_POSITION_EDGE); lcVector3 Max(LC_CAMERA_POSITION_EDGE, LC_CAMERA_POSITION_EDGE, LC_CAMERA_POSITION_EDGE); lcVector4 LocalPlanes[6]; for (int PlaneIdx = 0; PlaneIdx < 6; PlaneIdx++) { lcVector3 Normal = lcMul30(ObjectBoxTest.Planes[PlaneIdx], mWorldView); LocalPlanes[PlaneIdx] = lcVector4(Normal, ObjectBoxTest.Planes[PlaneIdx][3] - lcDot3(mWorldView[3], Normal)); } if (lcBoundingBoxIntersectsVolume(Min, Max, LocalPlanes)) { ObjectBoxTest.Objects.Add(const_cast(this)); return; } Min = lcVector3(-LC_CAMERA_TARGET_EDGE, -LC_CAMERA_TARGET_EDGE, -LC_CAMERA_TARGET_EDGE); Max = lcVector3(LC_CAMERA_TARGET_EDGE, LC_CAMERA_TARGET_EDGE, LC_CAMERA_TARGET_EDGE); lcMatrix44 WorldView = mWorldView; WorldView.SetTranslation(lcMul30(-mTargetPosition, WorldView)); for (int PlaneIdx = 0; PlaneIdx < 6; PlaneIdx++) { lcVector3 Normal = lcMul30(ObjectBoxTest.Planes[PlaneIdx], WorldView); LocalPlanes[PlaneIdx] = lcVector4(Normal, ObjectBoxTest.Planes[PlaneIdx][3] - lcDot3(WorldView[3], Normal)); } if (lcBoundingBoxIntersectsVolume(Min, Max, LocalPlanes)) { ObjectBoxTest.Objects.Add(const_cast(this)); return; } lcMatrix44 ViewWorld = lcMatrix44AffineInverse(mWorldView); lcVector3 UpVectorPosition = lcMul31(lcVector3(0, 25, 0), ViewWorld); WorldView = mWorldView; WorldView.SetTranslation(lcMul30(-UpVectorPosition, WorldView)); for (int PlaneIdx = 0; PlaneIdx < 6; PlaneIdx++) { lcVector3 Normal = lcMul30(ObjectBoxTest.Planes[PlaneIdx], WorldView); LocalPlanes[PlaneIdx] = lcVector4(Normal, ObjectBoxTest.Planes[PlaneIdx][3] - lcDot3(WorldView[3], Normal)); } if (lcBoundingBoxIntersectsVolume(Min, Max, LocalPlanes)) { ObjectBoxTest.Objects.Add(const_cast(this)); return; } } void lcCamera::InsertTime(lcStep Start, lcStep Time) { lcObject::InsertTime(mPositionKeys, Start, Time); lcObject::InsertTime(mTargetPositionKeys, Start, Time); lcObject::InsertTime(mUpVectorKeys, Start, Time); } void lcCamera::RemoveTime(lcStep Start, lcStep Time) { lcObject::RemoveTime(mPositionKeys, Start, Time); lcObject::RemoveTime(mTargetPositionKeys, Start, Time); lcObject::RemoveTime(mUpVectorKeys, Start, Time); } void lcCamera::ZoomExtents(float AspectRatio, const lcVector3& Center, const lcVector3* Points, int NumPoints, lcStep Step, bool AddKey) { if (IsOrtho()) { float MinX = FLT_MAX, MaxX = -FLT_MAX, MinY = FLT_MAX, MaxY = -FLT_MAX; for (int PointIdx = 0; PointIdx < NumPoints; PointIdx++) { lcVector3 Point = lcMul30(Points[PointIdx], mWorldView); MinX = lcMin(MinX, Point.x); MinY = lcMin(MinY, Point.y); MaxX = lcMax(MaxX, Point.x); MaxY = lcMax(MaxY, Point.y); } float Width = MaxX - MinX; float Height = MaxY - MinY; if (Width > Height * AspectRatio) Height = Width / AspectRatio; float f = Height / (m_fovy * (LC_PI / 180.0f)); lcVector3 FrontVector(mTargetPosition - mPosition); mPosition = Center - lcNormalize(FrontVector) * f; mTargetPosition = Center; } else { lcVector3 Position(mPosition + Center - mTargetPosition); lcMatrix44 ProjectionMatrix = lcMatrix44Perspective(m_fovy, AspectRatio, m_zNear, m_zFar); std::tie(mPosition, std::ignore) = lcZoomExtents(Position, mWorldView, ProjectionMatrix, Points, NumPoints); mTargetPosition = Center; } if (IsSimple()) AddKey = false; ChangeKey(mPositionKeys, mPosition, Step, AddKey); ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey); UpdatePosition(Step); } void lcCamera::ZoomRegion(float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners, lcStep Step, bool AddKey) { if (IsOrtho()) { float MinX = FLT_MAX, MaxX = -FLT_MAX, MinY = FLT_MAX, MaxY = -FLT_MAX; for (int PointIdx = 0; PointIdx < 2; PointIdx++) { lcVector3 Point = lcMul30(Corners[PointIdx], mWorldView); MinX = lcMin(MinX, Point.x); MinY = lcMin(MinY, Point.y); MaxX = lcMax(MaxX, Point.x); MaxY = lcMax(MaxY, Point.y); } float Width = MaxX - MinX; float Height = MaxY - MinY; if (Width > Height * AspectRatio) Height = Width / AspectRatio; float f = Height / (m_fovy * (LC_PI / 180.0f)); lcVector3 FrontVector(mTargetPosition - mPosition); mPosition = TargetPosition - lcNormalize(FrontVector) * f; mTargetPosition = TargetPosition; } else { lcMatrix44 WorldView = lcMatrix44LookAt(Position, TargetPosition, mUpVector); lcMatrix44 ProjectionMatrix = lcMatrix44Perspective(m_fovy, AspectRatio, m_zNear, m_zFar); std::tie(mPosition, std::ignore) = lcZoomExtents(Position, WorldView, ProjectionMatrix, Corners, 2); mTargetPosition = TargetPosition; } if (IsSimple()) AddKey = false; ChangeKey(mPositionKeys, mPosition, Step, AddKey); ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey); UpdatePosition(Step); } void lcCamera::Zoom(float Distance, lcStep Step, bool AddKey) { lcVector3 FrontVector(mPosition - mTargetPosition); FrontVector.Normalize(); FrontVector *= -5.0f * Distance; // Don't zoom ortho in if it would cross the ortho focal plane. if (IsOrtho()) { if ((Distance > 0) && (lcDot(mPosition + FrontVector - mTargetPosition, mPosition - mTargetPosition) <= 0)) return; mPosition += FrontVector; } else { mPosition += FrontVector; mTargetPosition += FrontVector; } if (IsSimple()) AddKey = false; ChangeKey(mPositionKeys, mPosition, Step, AddKey); ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey); UpdatePosition(Step); } void lcCamera::Pan(const lcVector3& Distance, lcStep Step, bool AddKey) { mPosition += Distance; mTargetPosition += Distance; if (IsSimple()) AddKey = false; ChangeKey(mPositionKeys, mPosition, Step, AddKey); ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey); UpdatePosition(Step); } void lcCamera::Orbit(float DistanceX, float DistanceY, const lcVector3& CenterPosition, lcStep Step, bool AddKey) { lcVector3 FrontVector(mPosition - mTargetPosition); lcVector3 Z(lcNormalize(lcVector3(FrontVector[0], FrontVector[1], 0))); if (qIsNaN(Z[0]) || qIsNaN(Z[1])) Z = lcNormalize(lcVector3(mUpVector[0], mUpVector[1], 0)); if (mUpVector[2] < 0) { Z[0] = -Z[0]; Z[1] = -Z[1]; } lcMatrix44 YRot(lcVector4(Z[0], Z[1], 0.0f, 0.0f), lcVector4(-Z[1], Z[0], 0.0f, 0.0f), lcVector4(0.0f, 0.0f, 1.0f, 0.0f), lcVector4(0.0f, 0.0f, 0.0f, 1.0f)); lcMatrix44 transform = lcMul(lcMul(lcMul(lcMatrix44AffineInverse(YRot), lcMatrix44RotationY(DistanceY)), YRot), lcMatrix44RotationZ(-DistanceX)); mPosition = lcMul31(mPosition - CenterPosition, transform) + CenterPosition; mTargetPosition = lcMul31(mTargetPosition - CenterPosition, transform) + CenterPosition; mUpVector = lcMul31(mUpVector, transform); if (IsSimple()) AddKey = false; ChangeKey(mPositionKeys, mPosition, Step, AddKey); ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey); ChangeKey(mUpVectorKeys, mUpVector, Step, AddKey); UpdatePosition(Step); } void lcCamera::Roll(float Distance, lcStep Step, bool AddKey) { lcVector3 FrontVector(mPosition - mTargetPosition); lcMatrix44 Rotation = lcMatrix44FromAxisAngle(FrontVector, Distance); mUpVector = lcMul30(mUpVector, Rotation); if (IsSimple()) AddKey = false; ChangeKey(mUpVectorKeys, mUpVector, Step, AddKey); UpdatePosition(Step); } void lcCamera::Center(lcVector3& point, lcStep Step, bool AddKey) { lcAlign(mTargetPosition, mPosition, point); if (IsSimple()) AddKey = false; ChangeKey(mPositionKeys, mPosition, Step, AddKey); ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey); UpdatePosition(Step); } void lcCamera::SetViewpoint(lcViewpoint Viewpoint) { lcVector3 Positions[] = { lcVector3( 0.0f, -1250.0f, 0.0f), // LC_VIEWPOINT_FRONT lcVector3( 0.0f, 1250.0f, 0.0f), // LC_VIEWPOINT_BACK lcVector3( 0.0f, 0.0f, 1250.0f), // LC_VIEWPOINT_TOP lcVector3( 0.0f, 0.0f, -1250.0f), // LC_VIEWPOINT_BOTTOM lcVector3( 1250.0f, 0.0f, 0.0f), // LC_VIEWPOINT_LEFT lcVector3(-1250.0f, 0.0f, 0.0f), // LC_VIEWPOINT_RIGHT lcVector3( 375.0f, -375.0f, 187.5f) // LC_VIEWPOINT_HOME }; lcVector3 Ups[] = { lcVector3(0.0f, 0.0f, 1.0f), lcVector3(0.0f, 0.0f, 1.0f), lcVector3(0.0f, 1.0f, 0.0f), lcVector3(0.0f,-1.0f, 0.0f), lcVector3(0.0f, 0.0f, 1.0f), lcVector3(0.0f, 0.0f, 1.0f), lcVector3(0.2357f, -0.2357f, 0.94281f) }; mPosition = Positions[Viewpoint]; mTargetPosition = lcVector3(0, 0, 0); mUpVector = Ups[Viewpoint]; ChangeKey(mPositionKeys, mPosition, 1, false); ChangeKey(mTargetPositionKeys, mTargetPosition, 1, false); ChangeKey(mUpVectorKeys, mUpVector, 1, false); UpdatePosition(1); } void lcCamera::SetViewpoint(const lcVector3& Position) { mPosition = Position; mTargetPosition = lcVector3(0, 0, 0); lcVector3 UpVector(0, 0, 1), FrontVector(Position), SideVector; FrontVector.Normalize(); if (fabsf(lcDot(UpVector, FrontVector)) > 0.99f) SideVector = lcVector3(-1, 0, 0); else SideVector = lcCross(FrontVector, UpVector); UpVector = lcCross(SideVector, FrontVector); UpVector.Normalize(); mUpVector = UpVector; ChangeKey(mPositionKeys, mPosition, 1, false); ChangeKey(mTargetPositionKeys, mTargetPosition, 1, false); ChangeKey(mUpVectorKeys, mUpVector, 1, false); UpdatePosition(1); } void lcCamera::SetAngles(float Latitude, float Longitude) { mPosition = lcVector3(0, -1, 0); mTargetPosition = lcVector3(0, 0, 0); mUpVector = lcVector3(0, 0, 1); lcMatrix33 LongitudeMatrix = lcMatrix33RotationZ(LC_DTOR * Longitude); mPosition = lcMul(mPosition, LongitudeMatrix); lcVector3 SideVector = lcMul(lcVector3(-1, 0, 0), LongitudeMatrix); lcMatrix33 LatitudeMatrix = lcMatrix33FromAxisAngle(SideVector, LC_DTOR * Latitude); mPosition = lcMul(mPosition, LatitudeMatrix); mUpVector = lcMul(mUpVector, LatitudeMatrix); ChangeKey(mPositionKeys, mPosition, 1, false); ChangeKey(mTargetPositionKeys, mTargetPosition, 1, false); ChangeKey(mUpVectorKeys, mUpVector, 1, false); UpdatePosition(1); } leocad-19.07.1/common/camera.h000066400000000000000000000173241351275256100160270ustar00rootroot00000000000000#pragma once #include "object.h" #include "lc_math.h" #include "lc_array.h" #define LC_CAMERA_HIDDEN 0x0001 #define LC_CAMERA_SIMPLE 0x0002 #define LC_CAMERA_ORTHO 0x0004 #define LC_CAMERA_POSITION_SELECTED 0x0010 #define LC_CAMERA_POSITION_FOCUSED 0x0020 #define LC_CAMERA_TARGET_SELECTED 0x0040 #define LC_CAMERA_TARGET_FOCUSED 0x0080 #define LC_CAMERA_UPVECTOR_SELECTED 0x0100 #define LC_CAMERA_UPVECTOR_FOCUSED 0x0200 #define LC_CAMERA_SELECTION_MASK (LC_CAMERA_POSITION_SELECTED | LC_CAMERA_TARGET_SELECTED | LC_CAMERA_UPVECTOR_SELECTED) #define LC_CAMERA_FOCUS_MASK (LC_CAMERA_POSITION_FOCUSED | LC_CAMERA_TARGET_FOCUSED | LC_CAMERA_UPVECTOR_FOCUSED) enum lcViewpoint { LC_VIEWPOINT_FRONT, LC_VIEWPOINT_BACK, LC_VIEWPOINT_TOP, LC_VIEWPOINT_BOTTOM, LC_VIEWPOINT_LEFT, LC_VIEWPOINT_RIGHT, LC_VIEWPOINT_HOME }; enum lcCameraSection { LC_CAMERA_SECTION_POSITION, LC_CAMERA_SECTION_TARGET, LC_CAMERA_SECTION_UPVECTOR }; class lcCamera : public lcObject { public: lcCamera(bool Simple); lcCamera(float ex, float ey, float ez, float tx, float ty, float tz); virtual ~lcCamera(); const char* GetName() const override { return m_strName; } void CreateName(const lcArray& Cameras); bool IsSimple() const { return (mState & LC_CAMERA_SIMPLE) != 0; } bool IsOrtho() const { return (mState & LC_CAMERA_ORTHO) != 0; } void SetOrtho(bool Ortho) { if (Ortho) mState |= LC_CAMERA_ORTHO; else mState &= ~LC_CAMERA_ORTHO; } virtual bool IsSelected() const override { return (mState & LC_CAMERA_SELECTION_MASK) != 0; } virtual bool IsSelected(quint32 Section) const override { switch (Section) { case LC_CAMERA_SECTION_POSITION: return (mState & LC_CAMERA_POSITION_SELECTED) != 0; break; case LC_CAMERA_SECTION_TARGET: return (mState & LC_CAMERA_TARGET_SELECTED) != 0; break; case LC_CAMERA_SECTION_UPVECTOR: return (mState & LC_CAMERA_UPVECTOR_SELECTED) != 0; break; } return false; } virtual void SetSelected(bool Selected) override { if (Selected) mState |= LC_CAMERA_SELECTION_MASK; else mState &= ~(LC_CAMERA_SELECTION_MASK | LC_CAMERA_FOCUS_MASK); } virtual void SetSelected(quint32 Section, bool Selected) override { switch (Section) { case LC_CAMERA_SECTION_POSITION: if (Selected) mState |= LC_CAMERA_POSITION_SELECTED; else mState &= ~(LC_CAMERA_POSITION_SELECTED | LC_CAMERA_POSITION_FOCUSED); break; case LC_CAMERA_SECTION_TARGET: if (Selected) mState |= LC_CAMERA_TARGET_SELECTED; else mState &= ~(LC_CAMERA_TARGET_SELECTED | LC_CAMERA_TARGET_FOCUSED); break; case LC_CAMERA_SECTION_UPVECTOR: if (Selected) mState |= LC_CAMERA_UPVECTOR_SELECTED; else mState &= ~(LC_CAMERA_UPVECTOR_SELECTED | LC_CAMERA_UPVECTOR_FOCUSED); break; } } virtual bool IsFocused() const override { return (mState & LC_CAMERA_FOCUS_MASK) != 0; } virtual bool IsFocused(quint32 Section) const override { switch (Section) { case LC_CAMERA_SECTION_POSITION: return (mState & LC_CAMERA_POSITION_FOCUSED) != 0; break; case LC_CAMERA_SECTION_TARGET: return (mState & LC_CAMERA_TARGET_FOCUSED) != 0; break; case LC_CAMERA_SECTION_UPVECTOR: return (mState & LC_CAMERA_UPVECTOR_FOCUSED) != 0; break; } return false; } virtual void SetFocused(quint32 Section, bool Focus) override { switch (Section) { case LC_CAMERA_SECTION_POSITION: if (Focus) mState |= LC_CAMERA_POSITION_SELECTED | LC_CAMERA_POSITION_FOCUSED; else mState &= ~(LC_CAMERA_POSITION_SELECTED | LC_CAMERA_POSITION_FOCUSED); break; case LC_CAMERA_SECTION_TARGET: if (Focus) mState |= LC_CAMERA_TARGET_SELECTED | LC_CAMERA_TARGET_FOCUSED; else mState &= ~(LC_CAMERA_TARGET_SELECTED | LC_CAMERA_TARGET_FOCUSED); break; case LC_CAMERA_SECTION_UPVECTOR: if (Focus) mState |= LC_CAMERA_UPVECTOR_SELECTED | LC_CAMERA_UPVECTOR_FOCUSED; else mState &= ~(LC_CAMERA_UPVECTOR_SELECTED | LC_CAMERA_UPVECTOR_FOCUSED); break; } } virtual quint32 GetFocusSection() const override { if (mState & LC_CAMERA_POSITION_FOCUSED) return LC_CAMERA_SECTION_POSITION; if (mState & LC_CAMERA_TARGET_FOCUSED) return LC_CAMERA_SECTION_TARGET; if (mState & LC_CAMERA_UPVECTOR_FOCUSED) return LC_CAMERA_SECTION_UPVECTOR; return ~0U; } virtual quint32 GetAllowedTransforms() const override { return LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Y | LC_OBJECT_TRANSFORM_MOVE_Z; } virtual lcVector3 GetSectionPosition(quint32 Section) const override { switch (Section) { case LC_CAMERA_SECTION_POSITION: return mPosition; case LC_CAMERA_SECTION_TARGET: return mTargetPosition; case LC_CAMERA_SECTION_UPVECTOR: return lcMul31(lcVector3(0, 25, 0), lcMatrix44AffineInverse(mWorldView)); } return lcVector3(0.0f, 0.0f, 0.0f); } void SaveLDraw(QTextStream& Stream) const; bool ParseLDrawLine(QTextStream& Stream); public: bool IsVisible() const { return (mState & LC_CAMERA_HIDDEN) == 0; } bool IsHidden() const { return (mState & LC_CAMERA_HIDDEN) != 0; } void SetHidden(bool Hidden) { if (Hidden) mState |= LC_CAMERA_HIDDEN; else mState &= ~LC_CAMERA_HIDDEN; } void SetPosition(const lcVector3& Position, lcStep Step, bool AddKey) { ChangeKey(mPositionKeys, Position, Step, AddKey); } void SetTargetPosition(const lcVector3& TargetPosition, lcStep Step, bool AddKey) { ChangeKey(mTargetPositionKeys, TargetPosition, Step, AddKey); } void SetUpVector(const lcVector3& UpVector, lcStep Step, bool AddKey) { ChangeKey(mPositionKeys, UpVector, Step, AddKey); } float GetOrthoHeight() const { // Compute the FOV/plane intersection radius. // d d // a = 2 atan(------) => ~ a = --- => d = af // 2f f float f = (mPosition - mTargetPosition).Length(); return (m_fovy * f) * (LC_PI / 180.0f); } public: virtual void RayTest(lcObjectRayTest& ObjectRayTest) const override; virtual void BoxTest(lcObjectBoxTest& ObjectBoxTest) const override; virtual void DrawInterface(lcContext* Context, const lcScene& Scene) const override; virtual void RemoveKeyFrames() override; void InsertTime(lcStep Start, lcStep Time); void RemoveTime(lcStep Start, lcStep Time); bool FileLoad(lcFile& file); void Select(bool bSelecting, bool bFocus, bool bMultiple); void CompareBoundingBox(lcVector3& Min, lcVector3& Max); void UpdatePosition(lcStep Step); void CopyPosition(const lcCamera* camera); void ZoomExtents(float AspectRatio, const lcVector3& Center, const lcVector3* Points, int NumPoints, lcStep Step, bool AddKey); void ZoomRegion(float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners, lcStep Step, bool AddKey); void Zoom(float Distance, lcStep Step, bool AddKey); void Pan(const lcVector3& Distance, lcStep Step, bool AddKey); void Orbit(float DistanceX, float DistanceY, const lcVector3& CenterPosition, lcStep Step, bool AddKey); void Roll(float Distance, lcStep Step, bool AddKey); void Center(lcVector3& point, lcStep Step, bool AddKey); void MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance); void MoveRelative(const lcVector3& Distance, lcStep Step, bool AddKey); void SetViewpoint(lcViewpoint Viewpoint); void SetViewpoint(const lcVector3& Position); void SetAngles(float Latitude, float Longitude); char m_strName[81]; float m_fovy; float m_zNear; float m_zFar; lcMatrix44 mWorldView; lcVector3 mPosition; lcVector3 mTargetPosition; lcVector3 mUpVector; protected: lcArray> mPositionKeys; lcArray> mTargetPositionKeys; lcArray> mUpVectorKeys; void Initialize(); quint32 mState; }; leocad-19.07.1/common/group.cpp000066400000000000000000000020471351275256100162620ustar00rootroot00000000000000#include "lc_global.h" #include #include "group.h" #include "lc_file.h" lcGroup::lcGroup() { mGroup = nullptr; } lcGroup::~lcGroup() { } void lcGroup::FileLoad(lcFile* File) { qint32 GroupIndex; char Name[LC_MAX_GROUP_NAME + 1]; File->ReadU8(); File->ReadBuffer(Name, sizeof(Name)); mName = QString::fromUtf8(Name); File->ReadVector3(); File->ReadS32(&GroupIndex, 1); mGroup = (lcGroup*)(quintptr)GroupIndex; } void lcGroup::CreateName(const lcArray& Groups) { if (!mName.isEmpty()) { bool Found = false; for (lcGroup* Group : Groups) { if (Group->mName == mName) { Found = true; break; } } if (!Found) return; } int Max = 0; QString Prefix = QApplication::tr("Group #"); int Length = Prefix.length(); for (lcGroup* Group : Groups) { const QString& Name = Group->mName; if (Name.startsWith(Prefix)) { bool Ok = false; int GroupNumber = Name.mid(Length).toInt(&Ok); if (Ok && GroupNumber > Max) Max = GroupNumber; } } mName = Prefix + QString::number(Max + 1); } leocad-19.07.1/common/group.h000066400000000000000000000004741351275256100157310ustar00rootroot00000000000000#pragma once #include "lc_array.h" #define LC_MAX_GROUP_NAME 64 class lcGroup { public: lcGroup(); ~lcGroup(); lcGroup* GetTopGroup() { return mGroup ? mGroup->GetTopGroup() : this; } void FileLoad(lcFile* File); void CreateName(const lcArray& Groups); lcGroup* mGroup; QString mName; }; leocad-19.07.1/common/image.cpp000066400000000000000000000065641351275256100162200ustar00rootroot00000000000000#include "lc_global.h" #include "image.h" #include "lc_file.h" static void CopyFromQImage(const QImage& Src, Image& Dest) { bool Alpha = Src.hasAlphaChannel(); Dest.Allocate(Src.width(), Src.height(), Alpha ? LC_PIXEL_FORMAT_R8G8B8A8 : LC_PIXEL_FORMAT_R8G8B8); quint8* Bytes = (quint8*)Dest.mData; for (int y = 0; y < Dest.mHeight; y++) { for (int x = 0; x < Dest.mWidth; x++) { QRgb Pixel = Src.pixel(x, y); *Bytes++ = qRed(Pixel); *Bytes++ = qGreen(Pixel); *Bytes++ = qBlue(Pixel); if (Alpha) *Bytes++ = qAlpha(Pixel); } } } Image::Image() { mData = nullptr; mWidth = 0; mHeight = 0; mFormat = LC_PIXEL_FORMAT_INVALID; } Image::Image(Image&& Other) { mData = Other.mData; mWidth = Other.mWidth; mHeight = Other.mHeight; mFormat = Other.mFormat; Other.mData = nullptr; Other.mWidth = 0; Other.mHeight = 0; Other.mFormat = LC_PIXEL_FORMAT_INVALID; } Image::~Image() { FreeData(); } int Image::GetBPP() const { switch (mFormat) { case LC_PIXEL_FORMAT_INVALID: return 0; case LC_PIXEL_FORMAT_A8: return 1; case LC_PIXEL_FORMAT_L8A8: return 2; case LC_PIXEL_FORMAT_R8G8B8: return 3; case LC_PIXEL_FORMAT_R8G8B8A8: return 4; } return 0; } bool Image::HasAlpha() const { switch (mFormat) { case LC_PIXEL_FORMAT_INVALID: return false; case LC_PIXEL_FORMAT_A8: return true; case LC_PIXEL_FORMAT_L8A8: return true; case LC_PIXEL_FORMAT_R8G8B8: return false; case LC_PIXEL_FORMAT_R8G8B8A8: return true; } return 0; } void Image::FreeData() { free(mData); mData = nullptr; mWidth = 0; mHeight = 0; mFormat = LC_PIXEL_FORMAT_INVALID; } void Image::Allocate(int Width, int Height, lcPixelFormat Format) { FreeData(); mWidth = Width; mHeight = Height; mFormat = Format; mData = (unsigned char*)malloc(mWidth * mHeight * GetBPP()); } void Image::ResizePow2() { int i, shifted_x, shifted_y; shifted_x = mWidth; for (i = 0; ((i < 16) && (shifted_x != 0)); i++) shifted_x = shifted_x >> 1; shifted_x = (i != 0) ? 1 << (i-1) : 1; shifted_y = mHeight; for (i = 0; ((i < 16) && (shifted_y != 0)); i++) shifted_y = shifted_y >> 1; shifted_y = (i != 0) ? 1 << (i-1) : 1; if ((shifted_x != mWidth) || (shifted_y != mHeight)) Resize (shifted_x, shifted_y); } void Image::Resize(int width, int height) { int i, j, k, components, stx, sty; float accumx, accumy; unsigned char* bits = nullptr; components = GetBPP(); int BufferSize = width * height * components; if (BufferSize) { bits = (unsigned char*)malloc(BufferSize); if (bits) { for (j = 0; j < mHeight; j++) { accumy = (float)height*j / (float)mHeight; sty = (int)floor(accumy); for (i = 0; i < mWidth; i++) { accumx = (float)width*i / (float)mWidth; stx = (int)floor(accumx); for (k = 0; k < components; k++) bits[(stx + sty*width)*components + k] = mData[(i + j * mWidth) * components + k]; } } } } free(mData); mData = bits; mWidth = width; mHeight = height; } bool Image::FileLoad(lcMemFile& File) { QImage Image; unsigned char* Buffer = File.mBuffer + File.mPosition; size_t BufferLength = File.mFileSize - File.mPosition; if (!Image.loadFromData(Buffer, (int)BufferLength)) return false; CopyFromQImage(Image, *this); return true; } bool Image::FileLoad(const QString& FileName) { QImage Image; if (!Image.load(FileName)) return false; CopyFromQImage(Image, *this); return true; } leocad-19.07.1/common/image.h000066400000000000000000000012211351275256100156460ustar00rootroot00000000000000#pragma once // Image Options #define LC_IMAGE_TRANSPARENT 0x2000 //#define LC_IMAGE_MASK 0x7000 enum lcPixelFormat { LC_PIXEL_FORMAT_INVALID, LC_PIXEL_FORMAT_A8, LC_PIXEL_FORMAT_L8A8, LC_PIXEL_FORMAT_R8G8B8, LC_PIXEL_FORMAT_R8G8B8A8 }; class Image { public: Image(); Image(Image&& Other); virtual ~Image(); int GetBPP() const; bool HasAlpha() const; bool FileLoad(lcMemFile& File); bool FileLoad(const QString& FileName); void Resize(int Width, int Height); void ResizePow2(); void Allocate(int Width, int Height, lcPixelFormat Format); void FreeData(); int mWidth; int mHeight; lcPixelFormat mFormat; unsigned char* mData; }; leocad-19.07.1/common/lc_application.cpp000066400000000000000000000545661351275256100201240ustar00rootroot00000000000000#include "lc_global.h" #include #include "lc_application.h" #include "lc_library.h" #include "lc_profile.h" #include "project.h" #include "lc_mainwindow.h" #include "lc_qpreferencesdialog.h" #include "lc_partselectionwidget.h" #include "lc_shortcuts.h" #include "view.h" lcApplication* gApplication; void lcPreferences::LoadDefaults() { mFixedAxes = lcGetProfileInt(LC_PROFILE_FIXED_AXES); mMouseSensitivity = lcGetProfileInt(LC_PROFILE_MOUSE_SENSITIVITY); mShadingMode = (lcShadingMode)lcGetProfileInt(LC_PROFILE_SHADING_MODE); mDrawAxes = lcGetProfileInt(LC_PROFILE_DRAW_AXES); mDrawEdgeLines = lcGetProfileInt(LC_PROFILE_DRAW_EDGE_LINES); mLineWidth = lcGetProfileFloat(LC_PROFILE_LINE_WIDTH); mDrawGridStuds = lcGetProfileInt(LC_PROFILE_GRID_STUDS); mGridStudColor = lcGetProfileInt(LC_PROFILE_GRID_STUD_COLOR); mDrawGridLines = lcGetProfileInt(LC_PROFILE_GRID_LINES); mGridLineSpacing = lcGetProfileInt(LC_PROFILE_GRID_LINE_SPACING); mGridLineColor = lcGetProfileInt(LC_PROFILE_GRID_LINE_COLOR); mViewSphereLocation = (lcViewSphereLocation)lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_LOCATION); mViewSphereSize = lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_SIZE); mViewSphereColor = lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_COLOR); mViewSphereTextColor = lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_TEXT_COLOR); mViewSphereHighlightColor = lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_HIGHLIGHT_COLOR); mAutoLoadMostRecent = lcGetProfileInt(LC_PROFILE_AUTOLOAD_MOSTRECENT); } void lcPreferences::SaveDefaults() { lcSetProfileInt(LC_PROFILE_FIXED_AXES, mFixedAxes); lcSetProfileInt(LC_PROFILE_MOUSE_SENSITIVITY, mMouseSensitivity); lcSetProfileInt(LC_PROFILE_SHADING_MODE, mShadingMode); lcSetProfileInt(LC_PROFILE_DRAW_AXES, mDrawAxes); lcSetProfileInt(LC_PROFILE_DRAW_EDGE_LINES, mDrawEdgeLines); lcSetProfileFloat(LC_PROFILE_LINE_WIDTH, mLineWidth); lcSetProfileInt(LC_PROFILE_GRID_STUDS, mDrawGridStuds); lcSetProfileInt(LC_PROFILE_GRID_STUD_COLOR, mGridStudColor); lcSetProfileInt(LC_PROFILE_GRID_LINES, mDrawGridLines); lcSetProfileInt(LC_PROFILE_GRID_LINE_SPACING, mGridLineSpacing); lcSetProfileInt(LC_PROFILE_GRID_LINE_COLOR, mGridLineColor); lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_LOCATION, (int)mViewSphereLocation); lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_SIZE, mViewSphereSize); lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_COLOR, mViewSphereColor); lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_TEXT_COLOR, mViewSphereTextColor); lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_HIGHLIGHT_COLOR, mViewSphereHighlightColor); lcSetProfileInt(LC_PROFILE_AUTOLOAD_MOSTRECENT, mAutoLoadMostRecent); } lcApplication::lcApplication(int& Argc, char** Argv) : QApplication(Argc, Argv) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) setApplicationDisplayName("LeoCAD"); #endif setOrganizationDomain("leocad.org"); setOrganizationName("LeoCAD Software"); setApplicationName("LeoCAD"); setApplicationVersion(LC_VERSION_TEXT); gApplication = this; mProject = nullptr; mLibrary = nullptr; mPreferences.LoadDefaults(); } lcApplication::~lcApplication() { delete mProject; delete mLibrary; gApplication = nullptr; } void lcApplication::SaveTabLayout() const { if (!mProject || mProject->GetFileName().isEmpty()) return; QSettings Settings; QByteArray TabLayout = gMainWindow->GetTabLayout(); Settings.setValue(GetTabLayoutKey(), TabLayout); } QString lcApplication::GetTabLayoutKey() const { if (mProject) { QString FileName = mProject->GetFileName(); if (!FileName.isEmpty()) { FileName.replace('\\', '?'); FileName.replace('/', '?'); return QString("TabLayouts/%1").arg(FileName); } } return QString(); } void lcApplication::SetProject(Project* Project) { SaveTabLayout(); gMainWindow->RemoveAllModelTabs(); delete mProject; mProject = Project; Project->SetActiveModel(0); lcGetPiecesLibrary()->RemoveTemporaryPieces(); if (mProject && !mProject->GetFileName().isEmpty()) { QSettings Settings; QByteArray TabLayout = Settings.value(GetTabLayoutKey()).toByteArray(); gMainWindow->RestoreTabLayout(TabLayout); } } void lcApplication::SetClipboard(const QByteArray& Clipboard) { mClipboard = Clipboard; gMainWindow->UpdatePaste(!mClipboard.isEmpty()); } void lcApplication::ExportClipboard(const QByteArray& Clipboard) { QMimeData* MimeData = new QMimeData(); MimeData->setData("application/vnd.leocad-clipboard", Clipboard); QApplication::clipboard()->setMimeData(MimeData); SetClipboard(Clipboard); } bool lcApplication::LoadPartsLibrary(const QList>& LibraryPaths, bool OnlyUsePaths, bool ShowProgress) { if (mLibrary == nullptr) mLibrary = new lcPiecesLibrary(); if (!OnlyUsePaths) { char* EnvPath = getenv("LEOCAD_LIB"); if (EnvPath && EnvPath[0]) return mLibrary->Load(EnvPath, ShowProgress); QString CustomPath = lcGetProfileString(LC_PROFILE_PARTS_LIBRARY); if (!CustomPath.isEmpty()) return mLibrary->Load(CustomPath, ShowProgress); } for (const QPair& LibraryPathEntry : LibraryPaths) { if (mLibrary->Load(LibraryPathEntry.first, ShowProgress)) { if (LibraryPathEntry.second) mLibrary->SetOfficialPieces(); return true; } } return false; } bool lcApplication::Initialize(QList>& LibraryPaths, bool& ShowWindow) { bool OnlyUseLibraryPaths = false; bool SaveImage = false; bool SaveWavefront = false; bool Save3DS = false; bool SaveCOLLADA = false; bool SaveHTML = false; bool SetCameraAngles = false; bool Orthographic = false; bool ImageHighlight = false; int ImageWidth = lcGetProfileInt(LC_PROFILE_IMAGE_WIDTH); int ImageHeight = lcGetProfileInt(LC_PROFILE_IMAGE_HEIGHT); int ImageStart = 0; int ImageEnd = 0; int PartImagesWidth = -1; int PartImagesHeight = -1; float CameraLatitude = 0.0f, CameraLongitude = 0.0f; QString ImageName; QString ModelName; QString CameraName; QString ViewpointName; QString ProjectName; QString SaveWavefrontName; QString Save3DSName; QString SaveCOLLADAName; QString SaveHTMLName; QStringList Arguments = arguments(); const int NumArguments = Arguments.size(); for (int ArgIdx = 1; ArgIdx < NumArguments; ArgIdx++) { const QString& Param = Arguments[ArgIdx]; if (Param.isEmpty()) continue; if (Param[0] != '-') { ProjectName = Param; continue; } auto ParseString = [&ArgIdx, &Arguments, NumArguments](QString& Value, bool Required) { if (ArgIdx < NumArguments - 1 && Arguments[ArgIdx + 1][0] != '-') { ArgIdx++; Value = Arguments[ArgIdx]; } else if (Required) printf("Not enough parameters for the '%s' argument.\n", Arguments[ArgIdx].toLatin1().constData()); }; auto ParseInteger = [&ArgIdx, &Arguments, NumArguments](int& Value) { if (ArgIdx < NumArguments - 1 && Arguments[ArgIdx + 1][0] != '-') { bool Ok = false; ArgIdx++; int NewValue = Arguments[ArgIdx].toInt(&Ok); if (Ok) Value = NewValue; else printf("Invalid value specified for the '%s' argument.\n", Arguments[ArgIdx - 1].toLatin1().constData()); } else printf("Not enough parameters for the '%s' argument.\n", Arguments[ArgIdx].toLatin1().constData()); }; auto ParseFloat = [&ArgIdx, &Arguments, NumArguments](float& Value) { if (ArgIdx < NumArguments - 1 && Arguments[ArgIdx + 1][0] != '-') { bool Ok = false; ArgIdx++; int NewValue = Arguments[ArgIdx].toFloat(&Ok); if (Ok) Value = NewValue; else printf("Invalid value specified for the '%s' argument.\n", Arguments[ArgIdx - 1].toLatin1().constData()); } else printf("Not enough parameters for the '%s' argument.\n", Arguments[ArgIdx].toLatin1().constData()); }; auto ParseVector2 = [&ArgIdx, &Arguments, NumArguments](float& Value1, float& Value2) { if (ArgIdx < NumArguments - 2 && Arguments[ArgIdx + 1][0] != '-' && Arguments[ArgIdx + 2][0] != '-') { bool Ok1 = false, Ok2 = false; ArgIdx++; float NewValue1 = Arguments[ArgIdx].toFloat(&Ok1); ArgIdx++; float NewValue2 = Arguments[ArgIdx].toFloat(&Ok2); if (Ok1 && Ok2) { Value1 = NewValue1; Value2 = NewValue2; return true; } else printf("Invalid value specified for the '%s' argument.\n", Arguments[ArgIdx - 2].toLatin1().constData()); } else printf("Not enough parameters for the '%s' argument.\n", Arguments[ArgIdx].toLatin1().constData()); return false; }; if (Param == QLatin1String("-l") || Param == QLatin1String("--libpath")) { QString LibPath; ParseString(LibPath, true); if (!LibPath.isEmpty()) { LibraryPaths.clear(); LibraryPaths += qMakePair(LibPath, false); OnlyUseLibraryPaths = true; } } else if (Param == QLatin1String("-i") || Param == QLatin1String("--image")) { SaveImage = true; ParseString(ImageName, false); } else if (Param == QLatin1String("-w") || Param == QLatin1String("--width")) ParseInteger(ImageWidth); else if (Param == QLatin1String("-h") || Param == QLatin1String("--height")) ParseInteger(ImageHeight); else if (Param == QLatin1String("-f") || Param == QLatin1String("--from")) ParseInteger(ImageStart); else if (Param == QLatin1String("-t") || Param == QLatin1String("--to")) ParseInteger(ImageEnd); else if (Param == QLatin1String("-s") || Param == QLatin1String("--submodel")) ParseString(ModelName, true); else if (Param == QLatin1String("-c") || Param == QLatin1String("--camera")) ParseString(CameraName, true); else if (Param == QLatin1String("--viewpoint")) ParseString(ViewpointName, true); else if (Param == QLatin1String("--camera-angles")) SetCameraAngles = ParseVector2(CameraLatitude, CameraLongitude); else if (Param == QLatin1String("--orthographic")) Orthographic = true; else if (Param == QLatin1String("--highlight")) ImageHighlight = true; else if (Param == QLatin1String("--shading")) { QString ShadingString; ParseString(ShadingString, true); if (ShadingString == QLatin1String("wireframe")) mPreferences.mShadingMode = LC_SHADING_WIREFRAME; else if (ShadingString == QLatin1String("flat")) mPreferences.mShadingMode = LC_SHADING_FLAT; else if (ShadingString == QLatin1String("default")) mPreferences.mShadingMode = LC_SHADING_DEFAULT_LIGHTS; else if (ShadingString == QLatin1String("full")) mPreferences.mShadingMode = LC_SHADING_FULL; } else if (Param == QLatin1String("--line-width")) ParseFloat(mPreferences.mLineWidth); else if (Param == QLatin1String("-obj") || Param == QLatin1String("--export-wavefront")) { SaveWavefront = true; ParseString(SaveWavefrontName, false); } else if (Param == QLatin1String("-3ds") || Param == QLatin1String("--export-3ds")) { Save3DS = true; ParseString(Save3DSName, false); } else if (Param == QLatin1String("-dae") || Param == QLatin1String("--export-collada")) { SaveCOLLADA = true; ParseString(SaveCOLLADAName, false); } else if (Param == QLatin1String("-html") || Param == QLatin1String("--export-html")) { SaveHTML = true; ParseString(SaveHTMLName, false); } else if (Param == QLatin1String("--html-parts-width")) ParseInteger(PartImagesWidth); else if (Param == QLatin1String("--html-parts-height")) ParseInteger(PartImagesHeight); else if (Param == QLatin1String("-v") || Param == QLatin1String("--version")) { #ifdef LC_CONTINUOUS_BUILD printf("LeoCAD Continuous Build " QT_STRINGIFY(LC_CONTINUOUS_BUILD) "\n"); #else printf("LeoCAD Version " LC_VERSION_TEXT "\n"); #endif printf("LeoCAD Version " LC_VERSION_TEXT "\n"); printf("Compiled " __DATE__ "\n"); ShowWindow = false; return true; } else if (Param == QLatin1String("-?") || Param == QLatin1String("--help")) { printf("Usage: leocad [options] [file]\n"); printf(" [options] can be:\n"); printf(" -l, --libpath : Set the Parts Library location to path.\n"); printf(" -i, --image : Save a picture in the format specified by ext.\n"); printf(" -w, --width : Set the picture width.\n"); printf(" -h, --height : Set the picture height.\n"); printf(" -f, --from