Merge pull request #2 from leozide/master

Merge latest upstream changes
This commit is contained in:
CansecoGPC 2021-02-25 18:30:07 +01:00 committed by GitHub
commit 6b3412ec2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
174 changed files with 40005 additions and 27885 deletions

34
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,34 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Version (please complete the following information):**
- OS: [e.g. Windows 10, Ubuntu, macOS]
- LeoCAD Version [e.g. 19.07 or continuous]
**Crash information:**
Some versions of LeoCAD will show a message that they saved a minidump file when they crash, if you see this message please attach the file.
**Additional context**
Add any other context about the problem here. If you're seeing a graphical issue, adding a screenshot of the About Dialog may help.

View file

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

1
.gitignore vendored
View file

@ -20,6 +20,7 @@
*.dae
*.3ds
*.obj
.vs
build
debug
release

View file

@ -1,20 +1,9 @@
language: cpp
matrix:
jobs:
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
name: Linux amd64
dist: trusty
addons:
apt:
@ -22,76 +11,90 @@ matrix:
- sourceline: "ppa:beineri/opt-qt-5.10.1-trusty"
packages:
- qt510base
sudo: required
compiler: gcc
env:
- QT_BASE=510
script:
- source /opt/qt*/bin/qt*-env.sh
- qmake PREFIX=/usr -v
- qmake PREFIX=/usr
- make -j$(nproc)
after_success:
- make install INSTALL_ROOT=AppDir
- wget https://github.com/leozide/leocad/releases/download/v19.07.1/Library-20.03.zip -O library.zip
- unzip library.zip
- mkdir -p AppDir/usr/share/leocad
- mv library.bin AppDir/usr/share/leocad/library.bin
- 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
- 'curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/leozide/leocad/commits/master -o repo.txt'
- 'export REMOTE=$(grep -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;
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
- bash upload.sh LeoCAD*.AppImage*
- os: linux
name: Linux arm64
arch: arm64
dist: focal
addons:
apt:
packages:
- qt5-default
- qtbase5-dev
- qttools5-dev-tools
- libqt5opengl5-dev
- zip
compiler: gcc
script:
- qmake -v
- qmake PREFIX=/usr
- make -j$(nproc)
after_success:
- cp build/release/leocad .
- export VERSION=$(git rev-parse --short HEAD)
- zip LeoCAD-Linux-$VERSION-arm64.zip leocad
- 'curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/leozide/leocad/commits/master -o repo.txt'
- 'export REMOTE=$(grep -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."; travis_terminate 0; fi;
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
- bash upload.sh LeoCAD*.zip
- os: osx
name: macOS
osx_image: xcode11
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
addons:
homebrew:
packages:
- grep
- qt5
install:
- brew link --force qt5
- wget https://github.com/leozide/povray/releases/download/continuous/povray
- wget https://github.com/leozide/leocad/releases/download/v19.07.1/Library-20.03.zip -O library.zip
- unzip library.zip
script:
- qmake -v
- qmake
- make -j$(sysctl -n hw.ncpu)
after_success:
- cd build/release
- macdeployqt LeoCAD.app -dmg
- mv LeoCAD.dmg LeoCAD-macOS-$(git rev-parse --short HEAD).dmg
- 'curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/leozide/leocad/commits/master -o repo.txt'
- 'export REMOTE=$(ggrep -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;
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
- bash upload.sh LeoCAD*.dmg*
branches:
except:

48
appveyor.yml Normal file
View file

@ -0,0 +1,48 @@
version: '{branch}.{build}'
skip_tags: true
image:
- Visual Studio 2019
configuration: Release
platform: x64
environment:
GITHUB_TOKEN:
secure: +EZPzYX4wUEc6MYg4kBLx9TogAqeeeWUPgtEW3VtAJATrBtxwpuOQIHrrR4hbc7a
before_build:
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
- set PATH=C:\Qt\5.15\msvc2019_64\bin;%PATH%
- git rev-parse --short HEAD > version.txt
- set /p VERSION= < version.txt
- qmake -v
- qmake -tp vc
build:
project: leocad.vcxproj
verbosity: minimal
after_build:
- 7z a symbols.zip build/release/leocad.exe build/release/leocad.pdb
- mkdir appdir
- copy build\release\leocad.exe appdir
- copy docs\readme.txt appdir
- appveyor DownloadFile https://github.com/leozide/leocad/releases/download/v19.07.1/Library-20.03.zip -FileName library.zip
- 7z e library.zip
- copy library.bin appdir\\library.bin
- appveyor DownloadFile https://github.com/leozide/povray/releases/download/continuous/povconsole32-sse2.exe -FileName appdir\povconsole32-sse2.exe
- windeployqt appdir\leocad.exe
- copy tools\setup\leocad.nsi .
- copy tools\setup\setup.ico .
- 'copy "%VCToolsRedistDir%\vcredist_x64.exe" appdir'
- '"C:\Program Files (x86)\NSIS\makensis.exe" /V4 /DX64 "/XOutFile LeoCAD-Windows-%VERSION%.exe" leocad.nsi'
- set TRAVIS_TAG=%APPVEYOR_REPO_TAG_NAME%
- set TRAVIS_REPO_SLUG=%APPVEYOR_REPO_NAME%
- set TRAVIS_COMMIT=%APPVEYOR_REPO_COMMIT%
- appveyor DownloadFile https://github.com/probonopd/uploadtool/raw/master/upload.sh
- if not defined APPVEYOR_PULL_REQUEST_NUMBER (bash upload.sh LeoCAD*.exe)
artifacts:
- path: symbols.zip
name: symbols
- path: LeoCAD-Windows-$(VERSION).exe
name: leocad

View file

@ -28,9 +28,9 @@ lcCamera::lcCamera(bool Simple)
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);
mPositionKeys.ChangeKey(mPosition, 1, true);
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, true);
mUpVectorKeys.ChangeKey(mUpVector, 1, true);
UpdatePosition(1);
}
@ -51,9 +51,9 @@ lcCamera::lcCamera(float ex, float ey, float ez, float tx, float ty, float tz)
Initialize();
ChangeKey(mPositionKeys, lcVector3(ex, ey, ez), 1, true);
ChangeKey(mTargetPositionKeys, lcVector3(tx, ty, tz), 1, true);
ChangeKey(mUpVectorKeys, UpVector, 1, true);
mPositionKeys.ChangeKey(lcVector3(ex, ey, ez), 1, true);
mTargetPositionKeys.ChangeKey(lcVector3(tx, ty, tz), 1, true);
mUpVectorKeys.ChangeKey(UpVector, 1, true);
UpdatePosition(1);
}
@ -62,23 +62,50 @@ lcCamera::~lcCamera()
{
}
lcViewpoint lcCamera::GetViewpoint(const QString& ViewpointName)
{
const QLatin1String ViewpointNames[] =
{
QLatin1String("front"),
QLatin1String("back"),
QLatin1String("top"),
QLatin1String("bottom"),
QLatin1String("left"),
QLatin1String("right"),
QLatin1String("home")
};
LC_ARRAY_SIZE_CHECK(ViewpointNames, lcViewpoint::Count);
for (int ViewpointIndex = 0; ViewpointIndex < static_cast<int>(lcViewpoint::Count); ViewpointIndex++)
if (ViewpointNames[ViewpointIndex] == ViewpointName)
return static_cast<lcViewpoint>(ViewpointIndex);
return lcViewpoint::Count;
}
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::SetName(const QString& Name)
{
mName = Name;
}
void lcCamera::CreateName(const lcArray<lcCamera*>& Cameras)
{
if (m_strName[0])
if (!mName.isEmpty())
{
bool Found = false;
for (int CameraIdx = 0; CameraIdx < Cameras.GetSize(); CameraIdx++)
for (const lcCamera* Camera : Cameras)
{
if (!strcmp(Cameras[CameraIdx]->m_strName, m_strName))
if (Camera->GetName() == mName)
{
Found = true;
break;
@ -89,16 +116,24 @@ void lcCamera::CreateName(const lcArray<lcCamera*>& Cameras)
return;
}
int i, max = 0;
const char* Prefix = "Camera ";
int MaxCameraNumber = 0;
const QLatin1String 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;
for (const lcCamera* Camera : Cameras)
{
QString CameraName = Camera->GetName();
sprintf(m_strName, "%s %d", Prefix, max+1);
if (CameraName.startsWith(Prefix))
{
bool Ok = false;
int CameraNumber = CameraName.midRef(Prefix.size()).toInt(&Ok);
if (Ok && CameraNumber > MaxCameraNumber)
MaxCameraNumber = CameraNumber;
}
}
mName = Prefix + QString::number(MaxCameraNumber + 1);
}
void lcCamera::SaveLDraw(QTextStream& Stream) const
@ -108,17 +143,17 @@ void lcCamera::SaveLDraw(QTextStream& Stream) const
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 ");
mPositionKeys.SaveKeysLDraw(Stream, "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 ");
mTargetPositionKeys.SaveKeysLDraw(Stream, "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 ");
mUpVectorKeys.SaveKeysLDraw(Stream, "CAMERA UP_VECTOR_KEY ");
else
Stream << QLatin1String("0 !LEOCAD CAMERA UP_VECTOR ") << mUpVector[0] << ' ' << mUpVector[1] << ' ' << mUpVector[2] << LineEnding;
@ -130,7 +165,7 @@ void lcCamera::SaveLDraw(QTextStream& Stream) const
if (IsOrtho())
Stream << QLatin1String("ORTHOGRAPHIC ");
Stream << QLatin1String("NAME ") << m_strName << LineEnding;
Stream << QLatin1String("NAME ") << mName << LineEnding;
}
bool lcCamera::ParseLDrawLine(QTextStream& Stream)
@ -153,30 +188,27 @@ bool lcCamera::ParseLDrawLine(QTextStream& Stream)
else if (Token == QLatin1String("POSITION"))
{
Stream >> mPosition[0] >> mPosition[1] >> mPosition[2];
ChangeKey(mPositionKeys, mPosition, 1, true);
mPositionKeys.ChangeKey(mPosition, 1, true);
}
else if (Token == QLatin1String("TARGET_POSITION"))
{
Stream >> mTargetPosition[0] >> mTargetPosition[1] >> mTargetPosition[2];
ChangeKey(mTargetPositionKeys, mTargetPosition, 1, true);
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, true);
}
else if (Token == QLatin1String("UP_VECTOR"))
{
Stream >> mUpVector[0] >> mUpVector[1] >> mUpVector[2];
ChangeKey(mUpVectorKeys, mUpVector, 1, true);
mUpVectorKeys.ChangeKey(mUpVector, 1, true);
}
else if (Token == QLatin1String("POSITION_KEY"))
LoadKeysLDraw(Stream, mPositionKeys);
mPositionKeys.LoadKeysLDraw(Stream);
else if (Token == QLatin1String("TARGET_POSITION_KEY"))
LoadKeysLDraw(Stream, mTargetPositionKeys);
mTargetPositionKeys.LoadKeysLDraw(Stream);
else if (Token == QLatin1String("UP_VECTOR_KEY"))
LoadKeysLDraw(Stream, mUpVectorKeys);
mUpVectorKeys.LoadKeysLDraw(Stream);
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;
mName = Stream.readAll().trimmed();
return true;
}
}
@ -212,13 +244,6 @@ bool lcCamera::FileLoad(lcFile& file)
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);
@ -232,40 +257,25 @@ bool lcCamera::FileLoad(lcFile& file)
if (version == 4)
{
file.ReadBuffer(m_strName, 80);
m_strName[80] = 0;
char Name[81];
file.ReadBuffer(Name, 80);
}
else
{
ch = file.ReadU8();
if (ch == 0xFF)
return false; // don't read CString
file.ReadBuffer(m_strName, ch);
m_strName[ch] = 0;
return false;
char Name[81];
file.ReadBuffer(Name, ch);
}
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)
@ -276,31 +286,12 @@ bool lcCamera::FileLoad(lcFile& file)
{
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
}
@ -308,9 +299,9 @@ bool lcCamera::FileLoad(lcFile& file)
if (version < 4)
{
m_fovy = (float)file.ReadDouble();
m_zFar = (float)file.ReadDouble();
m_zNear= (float)file.ReadDouble();
file.ReadDouble(); // m_fovy
file.ReadDouble(); // m_zFar
file.ReadDouble(); // m_zNear
}
else
{
@ -328,13 +319,6 @@ bool lcCamera::FileLoad(lcFile& file)
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();
@ -346,21 +330,18 @@ bool lcCamera::FileLoad(lcFile& file)
}
}
file.ReadFloats(&m_fovy, 1);
file.ReadFloats(&m_zFar, 1);
file.ReadFloats(&m_zNear, 1);
float f;
file.ReadFloats(&f, 1); // m_fovy
file.ReadFloats(&f, 1); // m_zFar
file.ReadFloats(&f, 1); // m_zNear
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();
}
}
@ -373,20 +354,6 @@ bool lcCamera::FileLoad(lcFile& file)
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;
@ -418,19 +385,19 @@ void lcCamera::MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance)
if (IsSelected(LC_CAMERA_SECTION_POSITION))
{
mPosition += Distance;
ChangeKey(mPositionKeys, mPosition, Step, AddKey);
mPositionKeys.ChangeKey(mPosition, Step, AddKey);
}
if (IsSelected(LC_CAMERA_SECTION_TARGET))
{
mTargetPosition += Distance;
ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey);
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
}
else if (IsSelected(LC_CAMERA_SECTION_UPVECTOR))
{
mUpVector += Distance;
mUpVector.Normalize();
ChangeKey(mUpVectorKeys, mUpVector, Step, AddKey);
mUpVectorKeys.ChangeKey(mUpVector, Step, AddKey);
}
lcVector3 FrontVector(mTargetPosition - mPosition);
@ -451,10 +418,10 @@ void lcCamera::MoveRelative(const lcVector3& Distance, lcStep Step, bool AddKey)
lcVector3 Relative = lcMul30(Distance, lcMatrix44Transpose(mWorldView)) * 5.0f;
mPosition += Relative;
ChangeKey(mPositionKeys, mPosition, Step, AddKey);
mPositionKeys.ChangeKey(mPosition, Step, AddKey);
mTargetPosition += Relative;
ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey);
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
UpdatePosition(Step);
}
@ -463,9 +430,9 @@ void lcCamera::UpdatePosition(lcStep Step)
{
if (!IsSimple())
{
mPosition = CalculateKey(mPositionKeys, Step);
mTargetPosition = CalculateKey(mTargetPositionKeys, Step);
mUpVector = CalculateKey(mUpVectorKeys, Step);
mPosition = mPositionKeys.CalculateKey(Step);
mTargetPosition = mTargetPositionKeys.CalculateKey(Step);
mUpVector = mUpVectorKeys.CalculateKey(Step);
}
lcVector3 FrontVector(mPosition - mTargetPosition);
@ -647,13 +614,13 @@ void lcCamera::DrawInterface(lcContext* Context, const lcScene& Scene) const
void lcCamera::RemoveKeyFrames()
{
mPositionKeys.RemoveAll();
ChangeKey(mPositionKeys, mPosition, 1, true);
mPositionKeys.ChangeKey(mPosition, 1, true);
mTargetPositionKeys.RemoveAll();
ChangeKey(mTargetPositionKeys, mTargetPosition, 1, true);
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, true);
mUpVectorKeys.RemoveAll();
ChangeKey(mUpVectorKeys, mUpVector, 1, true);
mUpVectorKeys.ChangeKey(mUpVector, 1, true);
}
void lcCamera::RayTest(lcObjectRayTest& ObjectRayTest) const
@ -763,27 +730,27 @@ void lcCamera::BoxTest(lcObjectBoxTest& ObjectBoxTest) const
void lcCamera::InsertTime(lcStep Start, lcStep Time)
{
lcObject::InsertTime(mPositionKeys, Start, Time);
lcObject::InsertTime(mTargetPositionKeys, Start, Time);
lcObject::InsertTime(mUpVectorKeys, Start, Time);
mPositionKeys.InsertTime(Start, Time);
mTargetPositionKeys.InsertTime(Start, Time);
mUpVectorKeys.InsertTime(Start, Time);
}
void lcCamera::RemoveTime(lcStep Start, lcStep Time)
{
lcObject::RemoveTime(mPositionKeys, Start, Time);
lcObject::RemoveTime(mTargetPositionKeys, Start, Time);
lcObject::RemoveTime(mUpVectorKeys, Start, Time);
mPositionKeys.RemoveTime(Start, Time);
mTargetPositionKeys.RemoveTime(Start, Time);
mUpVectorKeys.RemoveTime(Start, Time);
}
void lcCamera::ZoomExtents(float AspectRatio, const lcVector3& Center, const lcVector3* Points, int NumPoints, lcStep Step, bool AddKey)
void lcCamera::ZoomExtents(float AspectRatio, const lcVector3& Center, const std::vector<lcVector3>& Points, 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++)
for (lcVector3 Point : Points)
{
lcVector3 Point = lcMul30(Points[PointIdx], mWorldView);
Point = lcMul30(Point, mWorldView);
MinX = lcMin(MinX, Point.x);
MinY = lcMin(MinY, Point.y);
@ -791,8 +758,9 @@ void lcCamera::ZoomExtents(float AspectRatio, const lcVector3& Center, const lcV
MaxY = lcMax(MaxY, Point.y);
}
float Width = MaxX - MinX;
float Height = MaxY - MinY;
lcVector3 ViewCenter = lcMul30(Center, mWorldView);
float Width = qMax(fabsf(MaxX - ViewCenter.x), fabsf(ViewCenter.x - MinX)) * 2;
float Height = qMax(fabsf(MaxY - ViewCenter.y), fabsf(ViewCenter.y - MinY)) * 2;
if (Width > Height * AspectRatio)
Height = Width / AspectRatio;
@ -808,15 +776,15 @@ void lcCamera::ZoomExtents(float AspectRatio, const lcVector3& Center, const lcV
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);
std::tie(mPosition, std::ignore) = lcZoomExtents(Position, mWorldView, ProjectionMatrix, Points.data(), Points.size());
mTargetPosition = Center;
}
if (IsSimple())
AddKey = false;
ChangeKey(mPositionKeys, mPosition, Step, AddKey);
ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey);
mPositionKeys.ChangeKey(mPosition, Step, AddKey);
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
UpdatePosition(Step);
}
@ -861,8 +829,8 @@ void lcCamera::ZoomRegion(float AspectRatio, const lcVector3& Position, const lc
if (IsSimple())
AddKey = false;
ChangeKey(mPositionKeys, mPosition, Step, AddKey);
ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey);
mPositionKeys.ChangeKey(mPosition, Step, AddKey);
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
UpdatePosition(Step);
}
@ -890,8 +858,8 @@ void lcCamera::Zoom(float Distance, lcStep Step, bool AddKey)
if (IsSimple())
AddKey = false;
ChangeKey(mPositionKeys, mPosition, Step, AddKey);
ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey);
mPositionKeys.ChangeKey(mPosition, Step, AddKey);
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
UpdatePosition(Step);
}
@ -904,8 +872,8 @@ void lcCamera::Pan(const lcVector3& Distance, lcStep Step, bool AddKey)
if (IsSimple())
AddKey = false;
ChangeKey(mPositionKeys, mPosition, Step, AddKey);
ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey);
mPositionKeys.ChangeKey(mPosition, Step, AddKey);
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
UpdatePosition(Step);
}
@ -935,9 +903,9 @@ void lcCamera::Orbit(float DistanceX, float DistanceY, const lcVector3& CenterPo
if (IsSimple())
AddKey = false;
ChangeKey(mPositionKeys, mPosition, Step, AddKey);
ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey);
ChangeKey(mUpVectorKeys, mUpVector, Step, AddKey);
mPositionKeys.ChangeKey(mPosition, Step, AddKey);
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
mUpVectorKeys.ChangeKey(mUpVector, Step, AddKey);
UpdatePosition(Step);
}
@ -952,7 +920,7 @@ void lcCamera::Roll(float Distance, lcStep Step, bool AddKey)
if (IsSimple())
AddKey = false;
ChangeKey(mUpVectorKeys, mUpVector, Step, AddKey);
mUpVectorKeys.ChangeKey(mUpVector, Step, AddKey);
UpdatePosition(Step);
}
@ -962,18 +930,19 @@ void lcCamera::Center(const lcVector3& NewCenter, lcStep Step, bool AddKey)
const lcMatrix44 Inverse = lcMatrix44AffineInverse(mWorldView);
const lcVector3 Direction = -lcVector3(Inverse[2]);
float Yaw, Pitch, Roll;
// float Yaw, Pitch, Roll;
float Roll;
if (fabsf(Direction.z) < 0.9999f)
{
Yaw = atan2f(Direction.y, Direction.x);
Pitch = asinf(Direction.z);
// Yaw = atan2f(Direction.y, Direction.x);
// Pitch = asinf(Direction.z);
Roll = atan2f(Inverse[0][2], Inverse[1][2]);
}
else
{
Yaw = 0.0f;
Pitch = asinf(Direction.z);
// Yaw = 0.0f;
// Pitch = asinf(Direction.z);
Roll = atan2f(Inverse[0][1], Inverse[1][1]);
}
@ -995,8 +964,8 @@ void lcCamera::Center(const lcVector3& NewCenter, lcStep Step, bool AddKey)
if (IsSimple())
AddKey = false;
ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey);
ChangeKey(mUpVectorKeys, mUpVector, Step, AddKey);
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
mUpVectorKeys.ChangeKey(mUpVector, Step, AddKey);
UpdatePosition(Step);
}
@ -1005,13 +974,13 @@ 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( 0.0f, -1250.0f, 0.0f), // lcViewpoint::Front
lcVector3( 0.0f, 1250.0f, 0.0f), // lcViewpoint::Back
lcVector3( 0.0f, 0.0f, 1250.0f), // lcViewpoint::Top
lcVector3( 0.0f, 0.0f, -1250.0f), // lcViewpoint::Bottom
lcVector3( 1250.0f, 0.0f, 0.0f), // lcViewpoint::Left
lcVector3(-1250.0f, 0.0f, 0.0f), // lcViewpoint::Right
lcVector3( 375.0f, -375.0f, 187.5f) // lcViewpoint::Home
};
lcVector3 Ups[] =
@ -1025,13 +994,13 @@ void lcCamera::SetViewpoint(lcViewpoint Viewpoint)
lcVector3(0.2357f, -0.2357f, 0.94281f)
};
mPosition = Positions[Viewpoint];
mPosition = Positions[static_cast<int>(Viewpoint)];
mTargetPosition = lcVector3(0, 0, 0);
mUpVector = Ups[Viewpoint];
mUpVector = Ups[static_cast<int>(Viewpoint)];
ChangeKey(mPositionKeys, mPosition, 1, false);
ChangeKey(mTargetPositionKeys, mTargetPosition, 1, false);
ChangeKey(mUpVectorKeys, mUpVector, 1, false);
mPositionKeys.ChangeKey(mPosition, 1, false);
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, false);
mUpVectorKeys.ChangeKey(mUpVector, 1, false);
UpdatePosition(1);
}
@ -1051,9 +1020,28 @@ void lcCamera::SetViewpoint(const lcVector3& Position)
UpVector.Normalize();
mUpVector = UpVector;
ChangeKey(mPositionKeys, mPosition, 1, false);
ChangeKey(mTargetPositionKeys, mTargetPosition, 1, false);
ChangeKey(mUpVectorKeys, mUpVector, 1, false);
mPositionKeys.ChangeKey(mPosition, 1, false);
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, false);
mUpVectorKeys.ChangeKey(mUpVector, 1, false);
UpdatePosition(1);
}
void lcCamera::SetViewpoint(const lcVector3& Position, const lcVector3& Target, const lcVector3& Up)
{
mPosition = Position;
mTargetPosition = Target;
lcVector3 Direction = Target - Position;
lcVector3 UpVector, SideVector;
SideVector = lcCross(Direction, Up);
UpVector = lcCross(SideVector, Direction);
UpVector.Normalize();
mUpVector = UpVector;
mPositionKeys.ChangeKey(mPosition, 1, false);
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, false);
mUpVectorKeys.ChangeKey(mUpVector, 1, false);
UpdatePosition(1);
}
@ -1072,9 +1060,9 @@ void lcCamera::SetAngles(float Latitude, float Longitude, float Distance)
mPosition = lcMul(mPosition, LatitudeMatrix) * Distance;
mUpVector = lcMul(mUpVector, LatitudeMatrix);
ChangeKey(mPositionKeys, mPosition, 1, false);
ChangeKey(mTargetPositionKeys, mTargetPosition, 1, false);
ChangeKey(mUpVectorKeys, mUpVector, 1, false);
mPositionKeys.ChangeKey(mPosition, 1, false);
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, false);
mUpVectorKeys.ChangeKey(mUpVector, 1, false);
UpdatePosition(1);
}

View file

@ -17,15 +17,16 @@
#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
enum class lcViewpoint
{
LC_VIEWPOINT_FRONT,
LC_VIEWPOINT_BACK,
LC_VIEWPOINT_TOP,
LC_VIEWPOINT_BOTTOM,
LC_VIEWPOINT_LEFT,
LC_VIEWPOINT_RIGHT,
LC_VIEWPOINT_HOME
Front,
Back,
Top,
Bottom,
Left,
Right,
Home,
Count
};
enum lcCameraSection
@ -43,15 +44,16 @@ public:
~lcCamera();
lcCamera(const lcCamera&) = delete;
lcCamera(lcCamera&&) = delete;
lcCamera& operator=(const lcCamera&) = delete;
lcCamera& operator=(lcCamera&&) = delete;
const char* GetName() const override
static lcViewpoint GetViewpoint(const QString& ViewpointName);
QString GetName() const override
{
return m_strName;
return mName;
}
void SetName(const QString& Name);
void CreateName(const lcArray<lcCamera*>& Cameras);
bool IsSimple() const
@ -240,17 +242,17 @@ public:
void SetPosition(const lcVector3& Position, lcStep Step, bool AddKey)
{
ChangeKey(mPositionKeys, Position, Step, AddKey);
mPositionKeys.ChangeKey(Position, Step, AddKey);
}
void SetTargetPosition(const lcVector3& TargetPosition, lcStep Step, bool AddKey)
{
ChangeKey(mTargetPositionKeys, TargetPosition, Step, AddKey);
mTargetPositionKeys.ChangeKey(TargetPosition, Step, AddKey);
}
void SetUpVector(const lcVector3& UpVector, lcStep Step, bool AddKey)
{
ChangeKey(mPositionKeys, UpVector, Step, AddKey);
mPositionKeys.ChangeKey(UpVector, Step, AddKey);
}
float GetOrthoHeight() const
@ -272,15 +274,14 @@ public:
void InsertTime(lcStep Start, lcStep Time);
void RemoveTime(lcStep Start, lcStep Time);
bool FileLoad(lcFile& file);
void Select(bool bSelecting, bool bFocus, bool bMultiple);
static bool FileLoad(lcFile& file);
void CompareBoundingBox(lcVector3& Min, lcVector3& Max);
void UpdatePosition(lcStep Step);
void CopyPosition(const lcCamera* Camera);
void CopySettings(const lcCamera* Camera);
void ZoomExtents(float AspectRatio, const lcVector3& Center, const lcVector3* Points, int NumPoints, lcStep Step, bool AddKey);
void ZoomExtents(float AspectRatio, const lcVector3& Center, const std::vector<lcVector3>& Points, 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);
@ -291,11 +292,10 @@ public:
void MoveRelative(const lcVector3& Distance, lcStep Step, bool AddKey);
void SetViewpoint(lcViewpoint Viewpoint);
void SetViewpoint(const lcVector3& Position);
void SetViewpoint(const lcVector3& Position, const lcVector3& Target, const lcVector3& Up);
void GetAngles(float& Latitude, float& Longitude, float& Distance) const;
void SetAngles(float Latitude, float Longitude, float Distance);
char m_strName[81];
float m_fovy;
float m_zNear;
float m_zFar;
@ -306,12 +306,12 @@ public:
lcVector3 mUpVector;
protected:
lcArray<lcObjectKey<lcVector3>> mPositionKeys;
lcArray<lcObjectKey<lcVector3>> mTargetPositionKeys;
lcArray<lcObjectKey<lcVector3>> mUpVectorKeys;
lcObjectKeyArray<lcVector3> mPositionKeys;
lcObjectKeyArray<lcVector3> mTargetPositionKeys;
lcObjectKeyArray<lcVector3> mUpVectorKeys;
void Initialize();
QString mName;
quint32 mState;
};

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,11 @@
#pragma once
#include "lc_array.h"
#include "lc_math.h"
class Project;
class lcPiecesLibrary;
enum class lcViewSphereLocation;
enum class lcShadingMode
{
@ -13,12 +15,10 @@ enum class lcShadingMode
Full
};
enum class lcViewSphereLocation
enum class lcColorTheme
{
TopLeft,
TopRight,
BottomLeft,
BottomRight
Dark,
System
};
class lcPreferences
@ -26,22 +26,37 @@ class lcPreferences
public:
void LoadDefaults();
void SaveDefaults();
void SetInterfaceColors(lcColorTheme ColorTheme);
int mMouseSensitivity;
lcShadingMode mShadingMode;
bool mBackgroundGradient;
quint32 mBackgroundSolidColor;
quint32 mBackgroundGradientColorTop;
quint32 mBackgroundGradientColorBottom;
bool mDrawAxes;
quint32 mAxesColor;
quint32 mTextColor;
quint32 mMarqueeBorderColor;
quint32 mMarqueeFillColor;
quint32 mOverlayColor;
quint32 mActiveViewColor;
quint32 mInactiveViewColor;
bool mDrawEdgeLines;
float mLineWidth;
bool mAllowLOD;
float mMeshLODDistance;
bool mFadeSteps;
quint32 mFadeStepsColor;
bool mHighlightNewParts;
quint32 mHighlightNewPartsColor;
bool mGridEnabled = true;
bool mDrawGridStuds;
quint32 mGridStudColor;
bool mDrawGridLines;
int mGridLineSpacing;
quint32 mGridLineColor;
bool mDrawGridOrigin;
bool mFixedAxes;
bool mViewSphereEnabled;
lcViewSphereLocation mViewSphereLocation;
@ -51,6 +66,80 @@ public:
quint32 mViewSphereHighlightColor;
bool mAutoLoadMostRecent;
bool mRestoreTabLayout;
lcColorTheme mColorTheme;
int mPreviewViewSphereEnabled;
int mPreviewViewSphereSize;
lcViewSphereLocation mPreviewViewSphereLocation;
int mDrawPreviewAxis;
quint32 mStudCylinderColor;
quint32 mPartEdgeColor;
quint32 mBlackEdgeColor;
quint32 mDarkEdgeColor;
float mPartEdgeContrast;
float mPartColorValueLDIndex;
bool mAutomateEdgeColor;
};
struct lcCommandLineOptions
{
bool ParseOK;
bool Exit;
bool SaveImage;
bool SaveWavefront;
bool Save3DS;
bool SaveCOLLADA;
bool SaveHTML;
bool SetCameraAngles;
bool SetCameraPosition;
bool Orthographic;
bool SetFoV;
bool SetZPlanes;
bool SetFadeStepsColor;
bool SetHighlightColor;
bool FadeSteps;
bool ImageHighlight;
bool AutomateEdgeColor;
int ImageWidth;
int ImageHeight;
int AASamples;
lcShadingMode ShadingMode;
float LineWidth;
lcStudStyle StudStyle;
lcStep ImageStart;
lcStep ImageEnd;
lcVector3 CameraPosition[3];
lcVector2 CameraLatLon;
float FoV;
float PartEdgeContrast;
float PartColorValueLDIndex;
lcVector2 ZPlanes;
lcViewpoint Viewpoint;
quint32 StudCylinderColor;
quint32 PartEdgeColor;
quint32 BlackEdgeColor;
quint32 DarkEdgeColor;
quint32 FadeStepsColor;
quint32 HighlightColor;
QString ImageName;
QString ModelName;
QString CameraName;
QString ProjectName;
QString SaveWavefrontName;
QString Save3DSName;
QString SaveCOLLADAName;
QString SaveHTMLName;
QList<QPair<QString, bool>> LibraryPaths;
QString StdOut;
QString StdErr;
};
enum class lcStartupMode
{
ShowWindow,
Success,
Error
};
class lcApplication : public QApplication
@ -62,23 +151,29 @@ public:
~lcApplication();
void SetProject(Project* Project);
bool Initialize(QList<QPair<QString, bool>>& LibraryPaths, bool& ShowWindow);
static lcCommandLineOptions ParseCommandLineOptions();
lcStartupMode Initialize(const QList<QPair<QString, bool>>& LibraryPaths);
void Shutdown();
void ShowPreferencesDialog();
void SaveTabLayout() const;
bool LoadPartsLibrary(const QList<QPair<QString, bool>>& LibraryPaths, bool OnlyUsePaths, bool ShowProgress);
bool LoadPartsLibrary(const QList<QPair<QString, bool>>& LibraryPaths, bool OnlyUsePaths);
void SetClipboard(const QByteArray& Clipboard);
void ExportClipboard(const QByteArray& Clipboard);
Project* mProject;
lcPiecesLibrary* mLibrary;
Project* mProject = nullptr;
lcPiecesLibrary* mLibrary = nullptr;
lcPreferences mPreferences;
QByteArray mClipboard;
protected:
bool InitializeRenderer();
void ShutdownRenderer();
void UpdateStyle();
QString GetTabLayoutKey() const;
QString mDefaultStyle;
};
extern lcApplication* gApplication;
@ -97,4 +192,3 @@ inline lcPreferences& lcGetPreferences()
{
return gApplication->mPreferences;
}

View file

@ -1,47 +0,0 @@
#pragma once
#include "lc_math.h"
#include "lc_array.h"
#include "lc_application.h"
#include "lc_model.h"
#include "lc_category.h"
#include "lc_shortcuts.h"
#include "image.h"
struct lcPropertiesDialogOptions
{
lcModelProperties Properties;
bool SetDefault;
lcPartsList PartsList;
};
struct lcPreferencesDialogOptions
{
lcPreferences Preferences;
QString LibraryPath;
QString ColorConfigPath;
QString MinifigSettingsPath;
QString POVRayPath;
QString LGEOPath;
QString DefaultAuthor;
QString Language;
int CheckForUpdates;
int AASamples;
int StudLogo;
std::vector<lcLibraryCategory> Categories;
bool CategoriesModified;
bool CategoriesDefault;
lcKeyboardShortcuts KeyboardShortcuts;
bool KeyboardShortcutsModified;
bool KeyboardShortcutsDefault;
lcMouseShortcuts MouseShortcuts;
bool MouseShortcutsModified;
bool MouseShortcutsDefault;
};

View file

@ -0,0 +1,88 @@
#include "lc_global.h"
#include "lc_collapsiblewidget.h"
QImage lcCollapsibleWidget::mExpandedIcon;
QImage lcCollapsibleWidget::mCollapsedIcon;
lcCollapsibleWidget::lcCollapsibleWidget(const QString& Title, QWidget* Parent)
: QWidget(Parent)
{
QVBoxLayout* Layout = new QVBoxLayout(this);
// Layout->setSpacing(0);
Layout->setContentsMargins(0, 0, 0, 0);
QHBoxLayout* TitleLayout = new QHBoxLayout();
TitleLayout->setContentsMargins(0, 0, 0, 0);
Layout->addLayout(TitleLayout);
mTitleButton = new QToolButton(this);
mTitleButton->setText(Title);
mTitleButton->setAutoRaise(true);
mTitleButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
mTitleButton->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
TitleLayout->addWidget(mTitleButton);
connect(mTitleButton, SIGNAL(clicked()), this, SLOT(TitleClicked()));
mChildWidget = new QWidget(this);
Layout->addWidget(mChildWidget);
UpdateIcon();
}
void lcCollapsibleWidget::TitleClicked()
{
mExpanded = !mExpanded;
mChildWidget->setVisible(mExpanded);
UpdateIcon();
}
void lcCollapsibleWidget::Collapse()
{
if (mExpanded)
TitleClicked();
}
void lcCollapsibleWidget::SetChildLayout(QLayout* Layout)
{
Layout->setContentsMargins(12, 0, 0, 0);
mChildWidget->setLayout(Layout);
}
void lcCollapsibleWidget::UpdateIcon()
{
if (mExpanded)
{
if (mExpandedIcon.isNull())
{
QImage Image(16, 16, QImage::Format::Format_ARGB32);
Image.fill(QColor(0, 0, 0, 0));
uint Color = palette().color(QPalette::Text).rgba();
for (int y = 0; y < 8; y++)
for (int x = y; x < 8 - y; x++)
Image.setPixel(x + 4, y + 6, Color);
mExpandedIcon = Image;
}
mTitleButton->setIcon(QPixmap::fromImage(mExpandedIcon));
}
else
{
if (mCollapsedIcon.isNull())
{
QImage Image(16, 16, QImage::Format::Format_ARGB32);
Image.fill(QColor(0, 0, 0, 0));
uint Color = palette().color(QPalette::Text).rgba();
for (int y = 0; y < 8; y++)
for (int x = y; x < 8 - y; x++)
Image.setPixel(y + 6, x + 4, Color);
mCollapsedIcon = Image;
}
mTitleButton->setIcon(QPixmap::fromImage(mCollapsedIcon));
}
}

View file

@ -0,0 +1,25 @@
#pragma once
class lcCollapsibleWidget : public QWidget
{
Q_OBJECT
public:
lcCollapsibleWidget(const QString& RootTitle, QWidget* Parent = nullptr);
void Collapse();
void SetChildLayout(QLayout* Layout);
protected slots:
void TitleClicked();
protected:
void UpdateIcon();
QToolButton* mTitleButton = nullptr;
QWidget* mChildWidget = nullptr;
bool mExpanded = true;
static QImage mExpandedIcon;
static QImage mCollapsedIcon;
};

View file

@ -1,11 +1,12 @@
#include "lc_global.h"
#include "lc_colors.h"
#include "lc_file.h"
#include "lc_library.h"
#include "lc_application.h"
#include <float.h>
std::vector<lcColor> gColorList;
lcColorGroup gColorGroups[LC_NUM_COLORGROUPS];
int gNumUserColors;
int gEdgeColor;
int gDefaultColor;
@ -209,46 +210,54 @@ int lcGetBrickLinkColor(int ColorIndex)
return 0;
}
bool lcLoadColorFile(lcFile& File)
static void lcAdjustStudStyleColors(std::vector<lcColor>& Colors, lcStudStyle StudStyle)
{
const lcPreferences& Preferences = lcGetPreferences();
if (!Preferences.mAutomateEdgeColor && !lcIsHighContrast(StudStyle))
return;
const lcVector4 Edge = lcVector4FromColor(Preferences.mPartEdgeColor);
const lcVector4 DarkEdge = lcVector4FromColor(Preferences.mDarkEdgeColor);
const lcVector4 BlackEdge = lcVector4FromColor(Preferences.mBlackEdgeColor);
const float ContrastControl = Preferences.mPartEdgeContrast;
const float LightDarkControl = Preferences.mAutomateEdgeColor ? Preferences.mPartColorValueLDIndex : LC_SRGB_TO_LINEAR(Preferences.mPartColorValueLDIndex);
for (lcColor& Color : Colors)
{
lcVector3 LinearColor = lcSRGBToLinear(lcVector3(Color.Value));
const float ValueLuminescence = lcLuminescence(LinearColor);
if (Preferences.mAutomateEdgeColor)
{
if (Color.Adjusted)
continue;
const float EdgeLuminescence = lcLuminescence(lcSRGBToLinear(lcVector3(Color.Edge)));
Color.Edge = lcAlgorithmicEdgeColor(LinearColor, ValueLuminescence, EdgeLuminescence, ContrastControl, LightDarkControl);
Color.Adjusted = true;
}
else
{
if (Color.Code == 4242)
continue;
else if (Color.Code == 0)
Color.Edge = BlackEdge;
else if (ValueLuminescence < LightDarkControl)
Color.Edge = DarkEdge;
else
Color.Edge = Edge;
}
}
}
static std::vector<lcColor> lcParseColorFile(lcFile& File)
{
char Line[1024], Token[1024];
std::vector<lcColor>& Colors = gColorList;
lcColor Color, MainColor, EdgeColor;
Colors.clear();
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
gColorGroups[GroupIdx].Colors.clear();
gColorGroups[0].Name = QApplication::tr("Solid Colors", "Colors");
gColorGroups[1].Name = QApplication::tr("Translucent Colors", "Colors");
gColorGroups[2].Name = QApplication::tr("Special Colors", "Colors");
MainColor.Code = 16;
MainColor.Translucent = false;
MainColor.Value[0] = 1.0f;
MainColor.Value[1] = 1.0f;
MainColor.Value[2] = 0.5f;
MainColor.Value[3] = 1.0f;
MainColor.Edge[0] = 0.2f;
MainColor.Edge[1] = 0.2f;
MainColor.Edge[2] = 0.2f;
MainColor.Edge[3] = 1.0f;
strcpy(MainColor.Name, "Main Color");
strcpy(MainColor.SafeName, "Main_Color");
EdgeColor.Code = 24;
EdgeColor.Translucent = false;
EdgeColor.Value[0] = 0.5f;
EdgeColor.Value[1] = 0.5f;
EdgeColor.Value[2] = 0.5f;
EdgeColor.Value[3] = 1.0f;
EdgeColor.Edge[0] = 0.2f;
EdgeColor.Edge[1] = 0.2f;
EdgeColor.Edge[2] = 0.2f;
EdgeColor.Edge[3] = 1.0f;
strcpy(EdgeColor.Name, "Edge Color");
strcpy(EdgeColor.SafeName, "Edge_Color");
std::vector<lcColor> Colors;
lcColor Color;
while (File.ReadLine(Line, sizeof(Line)))
{
@ -263,11 +272,9 @@ bool lcLoadColorFile(lcFile& File)
if (strcmp(Token, "!COLOUR"))
continue;
bool GroupTranslucent = false;
bool GroupSpecial = false;
Color.Code = ~0U;
Color.Translucent = false;
Color.Group = LC_COLORGROUP_SOLID;
Color.Value[0] = FLT_MAX;
Color.Value[1] = FLT_MAX;
Color.Value[2] = FLT_MAX;
@ -335,18 +342,18 @@ bool lcLoadColorFile(lcFile& File)
Color.Translucent = true;
if (Value == 128)
GroupTranslucent = true;
Color.Group = LC_COLORGROUP_TRANSLUCENT;
else if (Value != 0)
GroupSpecial = true;
Color.Group = LC_COLORGROUP_SPECIAL;
}
else if (!strcmp(Token, "CHROME") || !strcmp(Token, "PEARLESCENT") || !strcmp(Token, "RUBBER") ||
!strcmp(Token, "MATTE_METALIC") || !strcmp(Token, "METAL") || !strcmp(Token, "LUMINANCE"))
!strcmp(Token, "MATTE_METALIC") || !strcmp(Token, "METAL") || !strcmp(Token, "LUMINANCE"))
{
GroupSpecial = true;
Color.Group = LC_COLORGROUP_SPECIAL;
}
else if (!strcmp(Token, "MATERIAL"))
{
GroupSpecial = true;
Color.Group = LC_COLORGROUP_SPECIAL;
break; // Material is always last so ignore it and the rest of the line.
}
}
@ -373,62 +380,165 @@ bool lcLoadColorFile(lcFile& File)
}
}
if (Duplicate)
continue;
if (Color.Code == 16)
{
MainColor = Color;
continue;
}
if (Color.Code == 24)
{
EdgeColor = Color;
continue;
}
Colors.push_back(Color);
if (GroupSpecial)
gColorGroups[LC_COLORGROUP_SPECIAL].Colors.push_back((int)Colors.size() - 1);
else if (GroupTranslucent)
gColorGroups[LC_COLORGROUP_TRANSLUCENT].Colors.push_back((int)Colors.size() - 1);
else
gColorGroups[LC_COLORGROUP_SOLID].Colors.push_back((int)Colors.size() - 1);
if (!Duplicate)
Colors.push_back(Color);
}
gDefaultColor = (int)Colors.size();
Colors.push_back(MainColor);
gColorGroups[LC_COLORGROUP_SOLID].Colors.push_back(gDefaultColor);
gNumUserColors = (int)Colors.size();
gEdgeColor = (int)Colors.size();
Colors.push_back(EdgeColor);
return Colors.size() > 2;
return Colors;
}
void lcLoadDefaultColors()
bool lcLoadColorFile(lcFile& File, lcStudStyle StudStyle)
{
QResource Resource(":/resources/ldconfig.ldr");
std::vector<lcColor> Colors = lcParseColorFile(File);
const bool Valid = !Colors.empty();
if (!Resource.isValid())
return;
if (Valid)
lcAdjustStudStyleColors(Colors, StudStyle);
QByteArray Data;
bool FoundMain = false, FoundEdge = false, FoundStud = false, FoundNoColor = false;
if (Resource.isCompressed())
Data = qUncompress(Resource.data(), Resource.size());
else
Data = QByteArray::fromRawData((const char*)Resource.data(), Resource.size());
for (const lcColor& Color : Colors)
{
switch (Color.Code)
{
case 16:
FoundMain = true;
break;
lcMemFile MemSettings;
case 24:
FoundEdge = true;
break;
MemSettings.WriteBuffer(Data.constData(), Data.size());
MemSettings.Seek(0, SEEK_SET);
lcLoadColorFile(MemSettings);
case 4242:
FoundStud = true;
break;
case LC_COLOR_NOCOLOR:
FoundNoColor = true;
break;
}
}
if (!FoundMain)
{
lcColor MainColor;
MainColor.Code = 16;
MainColor.Translucent = false;
MainColor.Group = LC_COLORGROUP_SOLID;
MainColor.Value[0] = 1.0f;
MainColor.Value[1] = 1.0f;
MainColor.Value[2] = 0.5f;
MainColor.Value[3] = 1.0f;
MainColor.Edge[0] = 0.2f;
MainColor.Edge[1] = 0.2f;
MainColor.Edge[2] = 0.2f;
MainColor.Edge[3] = 1.0f;
strcpy(MainColor.Name, "Main Color");
strcpy(MainColor.SafeName, "Main_Color");
Colors.push_back(MainColor);
}
if (!FoundEdge)
{
lcColor EdgeColor;
EdgeColor.Code = 24;
EdgeColor.Translucent = false;
EdgeColor.Group = LC_NUM_COLORGROUPS;
EdgeColor.Value[0] = 0.5f;
EdgeColor.Value[1] = 0.5f;
EdgeColor.Value[2] = 0.5f;
EdgeColor.Value[3] = 1.0f;
EdgeColor.Edge[0] = 0.2f;
EdgeColor.Edge[1] = 0.2f;
EdgeColor.Edge[2] = 0.2f;
EdgeColor.Edge[3] = 1.0f;
strcpy(EdgeColor.Name, "Edge Color");
strcpy(EdgeColor.SafeName, "Edge_Color");
Colors.push_back(EdgeColor);
}
if (!FoundStud)
{
const lcPreferences& Preferences = lcGetPreferences();
lcColor StudCylinderColor;
StudCylinderColor.Code = 4242;
StudCylinderColor.Translucent = false;
StudCylinderColor.Group = LC_NUM_COLORGROUPS;
StudCylinderColor.Value = lcVector4FromColor(Preferences.mStudCylinderColor);
StudCylinderColor.Edge = lcVector4FromColor(Preferences.mPartEdgeColor);
strcpy(StudCylinderColor.Name, "Stud Cylinder Color");
strcpy(StudCylinderColor.SafeName, "Stud_Cylinder_Color");
Colors.push_back(StudCylinderColor);
}
if (!FoundNoColor)
{
lcColor NoColor;
NoColor.Code = LC_COLOR_NOCOLOR;
NoColor.Translucent = false;
NoColor.Group = LC_NUM_COLORGROUPS;
NoColor.Value[0] = 0.5f;
NoColor.Value[1] = 0.5f;
NoColor.Value[2] = 0.5f;
NoColor.Value[3] = 1.0f;
NoColor.Edge[0] = 0.2f;
NoColor.Edge[1] = 0.2f;
NoColor.Edge[2] = 0.2f;
NoColor.Edge[3] = 1.0f;
strcpy(NoColor.Name, "No Color");
strcpy(NoColor.SafeName, "No_Color");
Colors.push_back(NoColor);
}
for (lcColor& Color : gColorList)
Color.Group = LC_NUM_COLORGROUPS;
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
gColorGroups[GroupIdx].Colors.clear();
gColorGroups[0].Name = QApplication::tr("Solid", "Colors");
gColorGroups[1].Name = QApplication::tr("Translucent", "Colors");
gColorGroups[2].Name = QApplication::tr("Special", "Colors");
for (lcColor& Color : Colors)
{
int ColorIndex;
for (ColorIndex = 0; ColorIndex < static_cast<int>(gColorList.size()); ColorIndex++)
if (gColorList[ColorIndex].Code == Color.Code)
break;
if (ColorIndex == static_cast<int>(gColorList.size()))
gColorList.push_back(Color);
else
gColorList[ColorIndex] = Color;
if (Color.Group != LC_NUM_COLORGROUPS)
gColorGroups[Color.Group].Colors.push_back(ColorIndex);
if (Color.Code == 16)
gDefaultColor = ColorIndex;
else if (Color.Code == 24)
gEdgeColor = ColorIndex;
}
return Valid;
}
void lcLoadDefaultColors(lcStudStyle StudStyle)
{
lcDiskFile ConfigFile(":/resources/ldconfig.ldr");
if (ConfigFile.Open(QIODevice::ReadOnly))
lcLoadColorFile(ConfigFile, StudStyle);
}
int lcGetColorIndex(quint32 ColorCode)
@ -449,8 +559,8 @@ int lcGetColorIndex(quint32 ColorCode)
if (ColorCode & LC_COLOR_DIRECT)
{
Color.Value[0] = (float)((ColorCode & 0xff0000) >> 16) / 255.0f;
Color.Value[1] = (float)((ColorCode & 0x00ff00) >> 8) / 255.0f;
Color.Value[2] = (float)((ColorCode & 0x0000ff) >> 0) / 255.0f;
Color.Value[1] = (float)((ColorCode & 0x00ff00) >> 8) / 255.0f;
Color.Value[2] = (float)((ColorCode & 0x0000ff) >> 0) / 255.0f;
Color.Value[3] = 1.0f;
sprintf(Color.Name, "Color %06X", ColorCode & 0xffffff);
sprintf(Color.SafeName, "Color_%06X", ColorCode & 0xffffff);

View file

@ -5,11 +5,14 @@
#define LC_MAX_COLOR_NAME 64
#define LC_COLOR_DIRECT 0x80000000
#define LC_COLOR_NOCOLOR 0xffffffff
struct lcColor
{
quint32 Code;
bool Translucent;
int Group;
bool Translucent = false;
bool Adjusted = false;
lcVector4 Value;
lcVector4 Edge;
char Name[LC_MAX_COLOR_NAME];
@ -44,25 +47,24 @@ enum lcInterfaceColor
extern lcVector4 gInterfaceColors[LC_NUM_INTERFACECOLORS];
extern std::vector<lcColor> gColorList;
extern lcColorGroup gColorGroups[LC_NUM_COLORGROUPS];
extern int gNumUserColors;
extern int gEdgeColor;
extern int gDefaultColor;
void lcLoadDefaultColors();
bool lcLoadColorFile(lcFile& File);
void lcLoadDefaultColors(lcStudStyle StudStyle);
bool lcLoadColorFile(lcFile& File, lcStudStyle StudStyle);
int lcGetColorIndex(quint32 ColorCode);
int lcGetBrickLinkColor(int ColorIndex);
inline quint32 lcGetColorCodeFromExtendedColor(int Color)
{
const int ConverstionTable[] = { 4, 12, 2, 10, 1, 9, 14, 15, 8, 0, 6, 13, 13, 334, 36, 44, 34, 42, 33, 41, 46, 47, 7, 382, 6, 13, 11, 383 };
return ConverstionTable[Color];
const quint32 ConversionTable[] = { 4, 12, 2, 10, 1, 9, 14, 15, 8, 0, 6, 13, 13, 334, 36, 44, 34, 42, 33, 41, 46, 47, 7, 382, 6, 13, 11, 383 };
return ConversionTable[Color];
}
inline quint32 lcGetColorCodeFromOriginalColor(int Color)
{
const int ConverstionTable[] = { 0, 2, 4, 9, 7, 6, 22, 8, 10, 11, 14, 16, 18, 9, 21, 20, 22, 8, 10, 11 };
return lcGetColorCodeFromExtendedColor(ConverstionTable[Color]);
const quint32 ConversionTable[] = { 0, 2, 4, 9, 7, 6, 22, 8, 10, 11, 14, 16, 18, 9, 21, 20, 22, 8, 10, 11 };
return lcGetColorCodeFromExtendedColor(ConversionTable[Color]);
}
inline quint32 lcGetColorCode(int ColorIndex)
@ -74,4 +76,3 @@ inline bool lcIsColorTranslucent(size_t ColorIndex)
{
return gColorList[ColorIndex].Translucent;
}

View file

@ -1,7 +1,7 @@
#include "lc_global.h"
#include "lc_commands.h"
lcCommand gCommands[LC_NUM_COMMANDS] =
const lcCommand gCommands[] =
{
// LC_FILE_NEW
{
@ -115,6 +115,13 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
QT_TRANSLATE_NOOP("Status", "Render the current model using POV-Ray"),
""
},
// LC_FILE_INSTRUCTIONS
{
QT_TRANSLATE_NOOP("Action", "File.Instructions"),
QT_TRANSLATE_NOOP("Menu", "&Instructions..."),
QT_TRANSLATE_NOOP("Status", "Configure instructions layout"),
""
},
// LC_FILE_PRINT
{
QT_TRANSLATE_NOOP("Action", "File.Print"),
@ -129,13 +136,6 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
QT_TRANSLATE_NOOP("Status", "Display how the model would look if printed"),
""
},
// LC_FILE_PRINT_BOM
{
QT_TRANSLATE_NOOP("Action", "File.PrintBOM"),
QT_TRANSLATE_NOOP("Menu", "Print &Bill of Materials..."),
QT_TRANSLATE_NOOP("Status", "Print a list of parts used"),
""
},
// LC_FILE_RECENT1
{
QT_TRANSLATE_NOOP("Action", "File.Recent1"),
@ -203,30 +203,65 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
{
QT_TRANSLATE_NOOP("Action", "Edit.Paste"),
QT_TRANSLATE_NOOP("Menu", "&Paste"),
QT_TRANSLATE_NOOP("Status", "Insert Clipboard contents"),
QT_TRANSLATE_NOOP("Status", "Insert Clipboard contents in the current step"),
"Ctrl+V"
},
// LC_EDIT_PASTE_STEPS
{
QT_TRANSLATE_NOOP("Action", "Edit.PasteSteps"),
QT_TRANSLATE_NOOP("Menu", "Paste with Steps"),
QT_TRANSLATE_NOOP("Status", "Insert Clipboard contents in their original steps"),
""
},
// LC_EDIT_FIND
{
QT_TRANSLATE_NOOP("Action", "Edit.Find"),
QT_TRANSLATE_NOOP("Menu", "&Find..."),
QT_TRANSLATE_NOOP("Status", "Find object"),
QT_TRANSLATE_NOOP("Menu", "&Find"),
QT_TRANSLATE_NOOP("Status", "Find piece"),
"Ctrl+F"
},
// LC_EDIT_FIND_NEXT
{
QT_TRANSLATE_NOOP("Action", "Edit.FindNext"),
QT_TRANSLATE_NOOP("Menu", "Find Ne&xt"),
QT_TRANSLATE_NOOP("Status", "Find next object"),
QT_TRANSLATE_NOOP("Status", "Find next piece"),
"F3"
},
// LC_EDIT_FIND_PREVIOUS
{
QT_TRANSLATE_NOOP("Action", "Edit.FindPrevious"),
QT_TRANSLATE_NOOP("Menu", "Find Pre&vious"),
QT_TRANSLATE_NOOP("Status", "Find object"),
QT_TRANSLATE_NOOP("Status", "Find previous piece"),
"Shift+F3"
},
// LC_EDIT_FIND_ALL
{
QT_TRANSLATE_NOOP("Action", "Edit.FindAll"),
QT_TRANSLATE_NOOP("Menu", "Find All"),
QT_TRANSLATE_NOOP("Status", "Find all pieces that match the search criteria"),
""
},
// LC_EDIT_REPLACE
{
QT_TRANSLATE_NOOP("Action", "Edit.Replace"),
QT_TRANSLATE_NOOP("Menu", "&Replace"),
QT_TRANSLATE_NOOP("Status", "Replace piece"),
""
},
// LC_EDIT_REPLACE_NEXT
{
QT_TRANSLATE_NOOP("Action", "Edit.ReplaceNext"),
QT_TRANSLATE_NOOP("Menu", "Replace Next"),
QT_TRANSLATE_NOOP("Status", "Replace next piece"),
""
},
// LC_EDIT_REPLACE_ALL
{
QT_TRANSLATE_NOOP("Action", "Edit.ReplaceAll"),
QT_TRANSLATE_NOOP("Menu", "Replace All"),
QT_TRANSLATE_NOOP("Status", "Replace all pieces that match the search criteria"),
""
},
// LC_EDIT_SELECT_ALL
{
QT_TRANSLATE_NOOP("Action", "Edit.SelectAll"),
@ -255,13 +290,6 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
QT_TRANSLATE_NOOP("Status", "Select objects by name"),
""
},
// LC_EDIT_SELECT_BY_COLOR
{
QT_TRANSLATE_NOOP("Action", "Edit.SelectByColor"),
QT_TRANSLATE_NOOP("Menu", "Select by Col&or..."),
QT_TRANSLATE_NOOP("Status", "Select pieces by color"),
""
},
// LC_EDIT_SELECT_SINGLE
{
QT_TRANSLATE_NOOP("Action", "Edit.SelectSingle"),
@ -290,18 +318,46 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
QT_TRANSLATE_NOOP("Status", "Select all pieces of the same type and color"),
""
},
// LC_EDIT_TRANSFORM_RELATIVE
{
QT_TRANSLATE_NOOP("Action", "Edit.TransformRelative"),
QT_TRANSLATE_NOOP("Menu", "Relative Transforms"),
QT_TRANSLATE_NOOP("Status", "Move and rotate objects relative to the one that has focus"),
// LC_EDIT_TRANSFORM_RELATIVE
{
QT_TRANSLATE_NOOP("Action", "Edit.TransformRelative"),
QT_TRANSLATE_NOOP("Menu", "Relative Transforms"),
QT_TRANSLATE_NOOP("Status", "Move and rotate objects relative to the one that has focus"),
""
},
// LC_EDIT_TRANSFORM_ABSOLUTE
{
QT_TRANSLATE_NOOP("Action", "Edit.TransformAbsolute"),
QT_TRANSLATE_NOOP("Menu", "Absolute Transforms"),
QT_TRANSLATE_NOOP("Status", "Move and rotate objects in absolute coordinates"),
""
},
// LC_EDIT_TRANSFORM_TOGGLE_RELATIVE
{
QT_TRANSLATE_NOOP("Action", "Edit.TransformToggleRelative"),
QT_TRANSLATE_NOOP("Menu", "Toggle Relative Transforms"),
QT_TRANSLATE_NOOP("Status", "Toggle moving and rotating objects relative to the one that has focus"),
""
},
// LC_EDIT_TRANSFORM_LOCAL
// LC_EDIT_TRANSFORM_SEPARATELY
{
QT_TRANSLATE_NOOP("Action", "Edit.TransformSeparately"),
QT_TRANSLATE_NOOP("Menu", "Rotate Separately"),
QT_TRANSLATE_NOOP("Status", "Rotate selected pieces separately"),
""
},
// LC_EDIT_TRANSFORM_TOGETHER
{
QT_TRANSLATE_NOOP("Action", "Edit.TransformTogether"),
QT_TRANSLATE_NOOP("Menu", "Rotate Together"),
QT_TRANSLATE_NOOP("Status", "Rotate selected pieces together"),
""
},
// LC_EDIT_TRANSFORM_TOGGLE_SEPARATE
{
QT_TRANSLATE_NOOP("Action", "Edit.TransformLocal"),
QT_TRANSLATE_NOOP("Menu", "Local Transforms"),
QT_TRANSLATE_NOOP("Status", "Rotate pieces around their individual pivot point"),
QT_TRANSLATE_NOOP("Action", "Edit.TransformToggleSeparate"),
QT_TRANSLATE_NOOP("Menu", "Toggle Separate Transforms"),
QT_TRANSLATE_NOOP("Status", "Toggle rotating selected pieces separately"),
""
},
// LC_EDIT_SNAP_MOVE_TOGGLE
@ -1011,6 +1067,62 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
QT_TRANSLATE_NOOP("Status", "Reset all views"),
""
},
// LC_VIEW_TOOLBAR_STANDARD
{
QT_TRANSLATE_NOOP("Action", "View.Toolbars.Standard"),
QT_TRANSLATE_NOOP("Menu", "Standard"),
QT_TRANSLATE_NOOP("Status", "Toggle the Standard Toolbar"),
""
},
// LC_VIEW_TOOLBAR_TOOLS
{
QT_TRANSLATE_NOOP("Action", "View.Toolbars.Tools"),
QT_TRANSLATE_NOOP("Menu", "Tools"),
QT_TRANSLATE_NOOP("Status", "Toggle the Tools Toolbar"),
""
},
// LC_VIEW_TOOLBAR_TIME
{
QT_TRANSLATE_NOOP("Action", "View.Toolbars.Time"),
QT_TRANSLATE_NOOP("Menu", "Time"),
QT_TRANSLATE_NOOP("Status", "Toggle the Time Toolbar"),
""
},
// LC_VIEW_TOOLBAR_PARTS
{
QT_TRANSLATE_NOOP("Action", "View.Toolbars.Parts"),
QT_TRANSLATE_NOOP("Menu", "Parts"),
QT_TRANSLATE_NOOP("Status", "Toggle the Parts Toolbar"),
""
},
// LC_VIEW_TOOLBAR_COLORS
{
QT_TRANSLATE_NOOP("Action", "View.Toolbars.Colors"),
QT_TRANSLATE_NOOP("Menu", "Colors"),
QT_TRANSLATE_NOOP("Status", "Toggle the Colors Toolbar"),
""
},
// LC_VIEW_TOOLBAR_PROPERTIES
{
QT_TRANSLATE_NOOP("Action", "View.Toolbars.Properties"),
QT_TRANSLATE_NOOP("Menu", "Properties"),
QT_TRANSLATE_NOOP("Status", "Toggle the Properties Toolbar"),
""
},
// LC_VIEW_TOOLBAR_TIMELINE
{
QT_TRANSLATE_NOOP("Action", "View.Toolbars.Timeline"),
QT_TRANSLATE_NOOP("Menu", "Timeline"),
QT_TRANSLATE_NOOP("Status", "Toggle the Timeline Toolbar"),
""
},
// LC_VIEW_TOOLBAR_PREVIEW
{
QT_TRANSLATE_NOOP("Action", "View.Toolbars.Preview"),
QT_TRANSLATE_NOOP("Menu", "Preview"),
QT_TRANSLATE_NOOP("Status", "Toggle the Preview Toolbar"),
""
},
// LC_VIEW_FULLSCREEN
{
QT_TRANSLATE_NOOP("Action", "View.FullScreen"),
@ -1067,6 +1179,20 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
QT_TRANSLATE_NOOP("Status", "Toggle the view sphere"),
""
},
// LC_VIEW_TOGGLE_AXIS_ICON
{
QT_TRANSLATE_NOOP("Action", "View.ToggleAxisIcon"),
QT_TRANSLATE_NOOP("Menu", "Axis Icon"),
QT_TRANSLATE_NOOP("Status", "Toggle axis icon"),
""
},
// LC_VIEW_TOGGLE_GRID
{
QT_TRANSLATE_NOOP("Action", "View.ToggleGrid"),
QT_TRANSLATE_NOOP("Menu", "Base Grid"),
QT_TRANSLATE_NOOP("Status", "Toggle grid"),
""
},
// LC_VIEW_FADE_PREVIOUS_STEPS
{
QT_TRANSLATE_NOOP("Action", "View.FadePreviousSteps"),
@ -1095,6 +1221,13 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
QT_TRANSLATE_NOOP("Status", "Create a copy of the selected pieces"),
"Ctrl+D"
},
// LC_PIECE_PAINT_SELECTED
{
QT_TRANSLATE_NOOP("Action", "Piece.PaintSelected"),
QT_TRANSLATE_NOOP("Menu", "&Paint Selected"),
QT_TRANSLATE_NOOP("Status", "Change the color of the selected pieces"),
""
},
// LC_PIECE_RESET_PIVOT_POINT
{
QT_TRANSLATE_NOOP("Action", "Piece.ResetPivotPoint"),
@ -1522,6 +1655,118 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_25
{
QT_TRANSLATE_NOOP("Action", "Model.Model25"),
QT_TRANSLATE_NOOP("Menu", "Model 25"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_26
{
QT_TRANSLATE_NOOP("Action", "Model.Model26"),
QT_TRANSLATE_NOOP("Menu", "Model 26"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_27
{
QT_TRANSLATE_NOOP("Action", "Model.Model27"),
QT_TRANSLATE_NOOP("Menu", "Model 27"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_28
{
QT_TRANSLATE_NOOP("Action", "Model.Model28"),
QT_TRANSLATE_NOOP("Menu", "Model 28"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_29
{
QT_TRANSLATE_NOOP("Action", "Model.Model29"),
QT_TRANSLATE_NOOP("Menu", "Model 29"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_30
{
QT_TRANSLATE_NOOP("Action", "Model.Model30"),
QT_TRANSLATE_NOOP("Menu", "Model 30"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_31
{
QT_TRANSLATE_NOOP("Action", "Model.Model31"),
QT_TRANSLATE_NOOP("Menu", "Model 31"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_32
{
QT_TRANSLATE_NOOP("Action", "Model.Model32"),
QT_TRANSLATE_NOOP("Menu", "Model 32"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_33
{
QT_TRANSLATE_NOOP("Action", "Model.Model33"),
QT_TRANSLATE_NOOP("Menu", "Model 33"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_34
{
QT_TRANSLATE_NOOP("Action", "Model.Model34"),
QT_TRANSLATE_NOOP("Menu", "Model 34"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_35
{
QT_TRANSLATE_NOOP("Action", "Model.Model35"),
QT_TRANSLATE_NOOP("Menu", "Model 35"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_36
{
QT_TRANSLATE_NOOP("Action", "Model.Model36"),
QT_TRANSLATE_NOOP("Menu", "Model 36"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_37
{
QT_TRANSLATE_NOOP("Action", "Model.Model37"),
QT_TRANSLATE_NOOP("Menu", "Model 37"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_38
{
QT_TRANSLATE_NOOP("Action", "Model.Model38"),
QT_TRANSLATE_NOOP("Menu", "Model 38"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_39
{
QT_TRANSLATE_NOOP("Action", "Model.Model39"),
QT_TRANSLATE_NOOP("Menu", "Model 39"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_MODEL_40
{
QT_TRANSLATE_NOOP("Action", "Model.Model40"),
QT_TRANSLATE_NOOP("Menu", "Model 40"),
QT_TRANSLATE_NOOP("Status", "Switch to this submodel"),
""
},
// LC_HELP_HOMEPAGE
{
QT_TRANSLATE_NOOP("Action", "Help.HomePage"),
@ -1587,25 +1832,25 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
}
};
static_assert(sizeof(gCommands)/sizeof(gCommands[0]) == LC_NUM_COMMANDS, "Array size mismatch.");
LC_ARRAY_SIZE_CHECK(gCommands, LC_NUM_COMMANDS);
const char* gToolNames[LC_NUM_TOOLS] =
const char* gToolNames[] =
{
QT_TRANSLATE_NOOP("Mouse", "NewPiece"), // LC_TOOL_INSERT
QT_TRANSLATE_NOOP("Mouse", "NewPointLight"), // LC_TOOL_LIGHT
QT_TRANSLATE_NOOP("Mouse", "NewSpotLight"), // LC_TOOL_SPOTLIGHT
QT_TRANSLATE_NOOP("Mouse", "NewCamera"), // LC_TOOL_CAMERA
QT_TRANSLATE_NOOP("Mouse", "Select"), // LC_TOOL_SELECT
QT_TRANSLATE_NOOP("Mouse", "Move"), // LC_TOOL_MOVE
QT_TRANSLATE_NOOP("Mouse", "Rotate"), // LC_TOOL_ROTATE
QT_TRANSLATE_NOOP("Mouse", "Delete"), // LC_TOOL_ERASER
QT_TRANSLATE_NOOP("Mouse", "Paint"), // LC_TOOL_PAINT
QT_TRANSLATE_NOOP("Mouse", "ColorPicker"), // LC_TOOL_COLOR_PICKER
QT_TRANSLATE_NOOP("Mouse", "Zoom"), // LC_TOOL_ZOOM
QT_TRANSLATE_NOOP("Mouse", "Pan"), // LC_TOOL_PAN
QT_TRANSLATE_NOOP("Mouse", "Orbit"), // LC_TOOL_ROTATE_VIEW
QT_TRANSLATE_NOOP("Mouse", "Roll"), // LC_TOOL_ROLL
QT_TRANSLATE_NOOP("Mouse", "ZoomRegion") // LC_TOOL_ZOOM_REGION
QT_TRANSLATE_NOOP("Mouse", "NewPiece"), // lcTool::Insert
QT_TRANSLATE_NOOP("Mouse", "NewPointLight"), // lcTool::Light
QT_TRANSLATE_NOOP("Mouse", "NewSpotLight"), // lcTool::SpotLight
QT_TRANSLATE_NOOP("Mouse", "NewCamera"), // lcTool::Camera
QT_TRANSLATE_NOOP("Mouse", "Select"), // lcTool::Select
QT_TRANSLATE_NOOP("Mouse", "Move"), // lcTool::Move
QT_TRANSLATE_NOOP("Mouse", "Rotate"), // lcTool::Rotate
QT_TRANSLATE_NOOP("Mouse", "Delete"), // lcTool::Eraser
QT_TRANSLATE_NOOP("Mouse", "Paint"), // lcTool::Paint
QT_TRANSLATE_NOOP("Mouse", "ColorPicker"), // lcTool::ColorPicker
QT_TRANSLATE_NOOP("Mouse", "Zoom"), // lcTool::Zoom
QT_TRANSLATE_NOOP("Mouse", "Pan"), // lcTool::Pan
QT_TRANSLATE_NOOP("Mouse", "Orbit"), // lcTool::RotateView
QT_TRANSLATE_NOOP("Mouse", "Roll"), // lcTool::Roll
QT_TRANSLATE_NOOP("Mouse", "ZoomRegion") // lcTool::ZoomRegion
};
static_assert(LC_ARRAY_COUNT(gToolNames) == LC_NUM_TOOLS, "Array size mismatch.");
LC_ARRAY_SIZE_CHECK(gToolNames, lcTool::Count);

View file

@ -18,9 +18,9 @@ enum lcCommandId
LC_FILE_EXPORT_POVRAY,
LC_FILE_EXPORT_WAVEFRONT,
LC_FILE_RENDER,
LC_FILE_INSTRUCTIONS,
LC_FILE_PRINT,
LC_FILE_PRINT_PREVIEW,
LC_FILE_PRINT_BOM,
LC_FILE_RECENT_FIRST,
LC_FILE_RECENT1 = LC_FILE_RECENT_FIRST,
LC_FILE_RECENT2,
@ -33,14 +33,18 @@ enum lcCommandId
LC_EDIT_CUT,
LC_EDIT_COPY,
LC_EDIT_PASTE,
LC_EDIT_PASTE_STEPS,
LC_EDIT_FIND,
LC_EDIT_FIND_NEXT,
LC_EDIT_FIND_PREVIOUS,
LC_EDIT_FIND_ALL,
LC_EDIT_REPLACE,
LC_EDIT_REPLACE_NEXT,
LC_EDIT_REPLACE_ALL,
LC_EDIT_SELECT_ALL,
LC_EDIT_SELECT_NONE,
LC_EDIT_SELECT_INVERT,
LC_EDIT_SELECT_BY_NAME,
LC_EDIT_SELECT_BY_COLOR,
LC_EDIT_SELECTION_MODE_FIRST,
LC_EDIT_SELECTION_SINGLE = LC_EDIT_SELECTION_MODE_FIRST,
LC_EDIT_SELECTION_PIECE,
@ -48,7 +52,11 @@ enum lcCommandId
LC_EDIT_SELECTION_PIECE_COLOR,
LC_EDIT_SELECTION_MODE_LAST = LC_EDIT_SELECTION_PIECE_COLOR,
LC_EDIT_TRANSFORM_RELATIVE,
LC_EDIT_TRANSFORM_LOCAL,
LC_EDIT_TRANSFORM_ABSOLUTE,
LC_EDIT_TRANSFORM_TOGGLE_RELATIVE,
LC_EDIT_TRANSFORM_SEPARATELY,
LC_EDIT_TRANSFORM_TOGETHER,
LC_EDIT_TRANSFORM_TOGGLE_SEPARATE,
LC_EDIT_SNAP_MOVE_TOGGLE,
LC_EDIT_SNAP_MOVE_XY0,
LC_EDIT_SNAP_MOVE_XY1,
@ -154,6 +162,16 @@ enum lcCommandId
LC_VIEW_SPLIT_VERTICAL,
LC_VIEW_REMOVE_VIEW,
LC_VIEW_RESET_VIEWS,
LC_VIEW_TOOLBAR_STANDARD,
LC_VIEW_TOOLBAR_FIRST = LC_VIEW_TOOLBAR_STANDARD,
LC_VIEW_TOOLBAR_TOOLS,
LC_VIEW_TOOLBAR_TIME,
LC_VIEW_TOOLBAR_PARTS,
LC_VIEW_TOOLBAR_COLORS,
LC_VIEW_TOOLBAR_PROPERTIES,
LC_VIEW_TOOLBAR_TIMELINE,
LC_VIEW_TOOLBAR_PREVIEW,
LC_VIEW_TOOLBAR_LAST = LC_VIEW_TOOLBAR_PREVIEW,
LC_VIEW_FULLSCREEN,
LC_VIEW_CLOSE_CURRENT_TAB,
LC_VIEW_SHADING_FIRST,
@ -166,10 +184,13 @@ enum lcCommandId
LC_VIEW_PROJECTION_ORTHO,
LC_VIEW_PROJECTION_LAST = LC_VIEW_PROJECTION_ORTHO,
LC_VIEW_TOGGLE_VIEW_SPHERE,
LC_VIEW_TOGGLE_AXIS_ICON,
LC_VIEW_TOGGLE_GRID,
LC_VIEW_FADE_PREVIOUS_STEPS,
LC_PIECE_INSERT,
LC_PIECE_DELETE,
LC_PIECE_DUPLICATE,
LC_PIECE_PAINT_SELECTED,
LC_PIECE_RESET_PIVOT_POINT,
LC_PIECE_REMOVE_KEY_FRAMES,
LC_PIECE_CONTROL_POINT_INSERT,
@ -232,7 +253,23 @@ enum lcCommandId
LC_MODEL_22,
LC_MODEL_23,
LC_MODEL_24,
LC_MODEL_LAST = LC_MODEL_24,
LC_MODEL_25,
LC_MODEL_26,
LC_MODEL_27,
LC_MODEL_28,
LC_MODEL_29,
LC_MODEL_30,
LC_MODEL_31,
LC_MODEL_32,
LC_MODEL_33,
LC_MODEL_34,
LC_MODEL_35,
LC_MODEL_36,
LC_MODEL_37,
LC_MODEL_38,
LC_MODEL_39,
LC_MODEL_40,
LC_MODEL_LAST = LC_MODEL_40,
LC_HELP_HOMEPAGE,
LC_HELP_BUG_REPORT,
LC_HELP_UPDATES,
@ -253,27 +290,27 @@ struct lcCommand
const char* DefaultShortcut;
};
extern lcCommand gCommands[LC_NUM_COMMANDS];
extern const lcCommand gCommands[];
enum lcTool
enum class lcTool
{
LC_TOOL_INSERT,
LC_TOOL_LIGHT,
LC_TOOL_SPOTLIGHT,
LC_TOOL_CAMERA,
LC_TOOL_SELECT,
LC_TOOL_MOVE,
LC_TOOL_ROTATE,
LC_TOOL_ERASER,
LC_TOOL_PAINT,
LC_TOOL_COLOR_PICKER,
LC_TOOL_ZOOM,
LC_TOOL_PAN,
LC_TOOL_ROTATE_VIEW,
LC_TOOL_ROLL,
LC_TOOL_ZOOM_REGION,
LC_NUM_TOOLS
Insert,
Light,
SpotLight,
Camera,
Select,
Move,
Rotate,
Eraser,
Paint,
ColorPicker,
Zoom,
Pan,
RotateView,
Roll,
ZoomRegion,
Count
};
extern const char* gToolNames[LC_NUM_TOOLS];
extern const char* gToolNames[];

View file

@ -6,6 +6,12 @@
#include "lc_colors.h"
#include "lc_mainwindow.h"
#include "lc_library.h"
#include "texfont.h"
#include "lc_view.h"
#include "lc_viewsphere.h"
#include "lc_stringcache.h"
#include "lc_partselectionwidget.h"
#include <QOpenGLFunctions_3_2_Core>
#ifdef LC_OPENGLES
#define glEnableClientState(...)
@ -18,7 +24,10 @@
#define GL_STATIC_DRAW_ARB GL_STATIC_DRAW
#endif
std::unique_ptr<QOpenGLContext> lcContext::mOffscreenContext;
std::unique_ptr<QOffscreenSurface> lcContext::mOffscreenSurface;
lcProgram lcContext::mPrograms[static_cast<int>(lcMaterialType::Count)];
int lcContext::mValidContexts;
lcContext::lcContext()
{
@ -33,18 +42,17 @@ lcContext::lcContext()
mColorEnabled = false;
mTexture2D = 0;
mTexture2DMS = 0;
mTextureCubeMap = 0;
mPolygonOffset = lcPolygonOffset::None;
mDepthWrite = true;
mDepthFunction = lcDepthFunction::LessEqual;
mCullFace = false;
mLineWidth = 1.0f;
#ifndef LC_OPENGLES
mMatrixMode = GL_MODELVIEW;
mTextureEnabled = false;
#endif
mFramebufferObject = 0;
mColor = lcVector4(0.0f, 0.0f, 0.0f, 0.0f);
mWorldMatrix = lcMatrix44Identity();
mViewMatrix = lcMatrix44Identity();
@ -66,6 +74,58 @@ lcContext::lcContext()
lcContext::~lcContext()
{
if (mValid)
{
mValidContexts--;
if (!mValidContexts)
{
gStringCache.Reset();
gTexFont.Reset();
lcGetPiecesLibrary()->ReleaseBuffers(this);
lcView::DestroyResources(this);
DestroyResources();
lcViewSphere::DestroyResources(this);
}
}
}
bool lcContext::CreateOffscreenContext()
{
std::unique_ptr<QOpenGLContext> OffscreenContext(new QOpenGLContext());
if (!OffscreenContext)
return false;
OffscreenContext->setShareContext(QOpenGLContext::globalShareContext());
if (!OffscreenContext->create() || !OffscreenContext->isValid())
return false;
std::unique_ptr<QOffscreenSurface> OffscreenSurface(new QOffscreenSurface());
if (!OffscreenSurface)
return false;
OffscreenSurface->create();
if (!OffscreenSurface->isValid())
return false;
if (!OffscreenContext->makeCurrent(OffscreenSurface.get()))
return false;
mOffscreenContext = std::move(OffscreenContext);
mOffscreenSurface = std::move(OffscreenSurface);
return true;
}
void lcContext::DestroyOffscreenContext()
{
mOffscreenSurface.reset();
mOffscreenContext.reset();
}
void lcContext::CreateShaderPrograms()
@ -102,7 +162,7 @@ void lcContext::CreateShaderPrograms()
" LC_SHADER_PRECISION float Diffuse = min(abs(dot(Normal, LightDirection)) * 0.6 + 0.65, 1.0);\n"
};
const char* const VertexShaders[static_cast<int>(lcMaterialType::Count)] =
const char* const VertexShaders[] =
{
":/resources/shaders/unlit_color_vs.glsl", // UnlitColor
":/resources/shaders/unlit_texture_modulate_vs.glsl", // UnlitTextureModulate
@ -113,7 +173,9 @@ void lcContext::CreateShaderPrograms()
":/resources/shaders/fakelit_texture_decal_vs.glsl" // FakeLitTextureDecal
};
const char* const FragmentShaders[static_cast<int>(lcMaterialType::Count)] =
LC_ARRAY_SIZE_CHECK(VertexShaders, lcMaterialType::Count);
const char* const FragmentShaders[] =
{
":/resources/shaders/unlit_color_ps.glsl", // UnlitColor
":/resources/shaders/unlit_texture_modulate_ps.glsl", // UnlitTextureModulate
@ -124,21 +186,16 @@ void lcContext::CreateShaderPrograms()
":/resources/shaders/fakelit_texture_decal_ps.glsl" // FakeLitTextureDecal
};
const auto LoadShader = [ShaderPrefix](const char* FileName, GLuint ShaderType) -> GLuint
{
QResource Resource(FileName);
LC_ARRAY_SIZE_CHECK(FragmentShaders, lcMaterialType::Count);
if (!Resource.isValid())
const auto LoadShader = [this, ShaderPrefix](const char* FileName, GLuint ShaderType) -> GLuint
{
QFile ShaderFile(FileName);
if (!ShaderFile.open(QIODevice::ReadOnly))
return 0;
QByteArray Data;
if (Resource.isCompressed())
Data = qUncompress(Resource.data(), Resource.size());
else
Data = QByteArray::fromRawData((const char*)Resource.data(), Resource.size());
Data = ShaderPrefix + Data;
QByteArray Data = ShaderPrefix + ShaderFile.readAll();
const char* Source = Data.constData();
const GLuint Shader = glCreateShader(ShaderType);
@ -233,10 +290,60 @@ void lcContext::DestroyResources()
}
}
void lcContext::MakeCurrent()
{
if (mWidget)
mWidget->makeCurrent();
else
mOffscreenContext->makeCurrent(mOffscreenSurface.get());
}
void lcContext::SetGLContext(QOpenGLContext* Context, QOpenGLWidget* Widget)
{
mContext = Context;
mWidget = Widget;
MakeCurrent();
initializeOpenGLFunctions();
if (!mValidContexts)
{
lcInitializeGLExtensions(Context);
// TODO: Find a better place for the grid texture and font
gStringCache.Initialize(this);
gTexFont.Initialize(this);
CreateResources();
lcView::CreateResources(this);
lcViewSphere::CreateResources(this);
if (!gSupportsShaderObjects && lcGetPreferences().mShadingMode == lcShadingMode::DefaultLights)
lcGetPreferences().mShadingMode = lcShadingMode::Flat;
if (!gSupportsFramebufferObject)
gMainWindow->GetPartSelectionWidget()->DisableIconMode();
}
mValid = true;
mValidContexts++;
}
void lcContext::SetOffscreenContext()
{
SetGLContext(mOffscreenContext.get(), nullptr);
}
void lcContext::SetDefaultState()
{
#ifndef LC_OPENGLES
if (QSurfaceFormat::defaultFormat().samples() > 1)
glEnable(GL_LINE_SMOOTH);
#endif
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
mDepthFunction = lcDepthFunction::LessEqual;
if (gSupportsBlendFuncSeparate)
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
@ -283,13 +390,6 @@ void lcContext::SetDefaultState()
glBindTexture(GL_TEXTURE_2D, 0);
mTexture2D = 0;
#ifndef LC_OPENGLES
if (gSupportsTexImage2DMultisample)
{
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
mTexture2DMS = 0;
}
#endif
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
mTextureCubeMap = 0;
@ -299,6 +399,9 @@ void lcContext::SetDefaultState()
mDepthWrite = true;
glDepthMask(GL_TRUE);
glDisable(GL_CULL_FACE);
mCullFace = false;
glLineWidth(1.0f);
mLineWidth = 1.0f;
@ -320,12 +423,22 @@ void lcContext::SetDefaultState()
}
}
void lcContext::ClearColorAndDepth(const lcVector4& ClearColor)
{
glClearColor(ClearColor[0], ClearColor[1], ClearColor[2], ClearColor[3]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void lcContext::ClearDepth()
{
glClear(GL_DEPTH_BUFFER_BIT);
}
void lcContext::ClearResources()
{
ClearVertexBuffer();
ClearIndexBuffer();
BindTexture2D(0);
BindTexture2DMS(0);
}
void lcContext::SetMaterial(lcMaterialType MaterialType)
@ -426,6 +539,38 @@ void lcContext::SetDepthWrite(bool Enable)
mDepthWrite = Enable;
}
void lcContext::SetDepthFunction(lcDepthFunction DepthFunction)
{
if (DepthFunction == mDepthFunction)
return;
switch (DepthFunction)
{
case lcDepthFunction::Always:
glDepthFunc(GL_ALWAYS);
break;
case lcDepthFunction::LessEqual:
glDepthFunc(GL_LEQUAL);
break;
}
mDepthFunction = DepthFunction;
}
void lcContext::EnableCullFace(bool Enable)
{
if (Enable == mCullFace)
return;
if (Enable)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
mCullFace = Enable;
}
void lcContext::SetLineWidth(float LineWidth)
{
if (LineWidth == mLineWidth)
@ -452,20 +597,6 @@ void lcContext::BindTexture2D(GLuint Texture)
mTexture2D = Texture;
}
void lcContext::BindTexture2DMS(GLuint Texture)
{
if (mTexture2DMS == Texture)
return;
#ifndef LC_OPENGLES
if (gSupportsTexImage2DMultisample)
{
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, Texture);
mTexture2DMS = Texture;
}
#endif
}
void lcContext::BindTextureCubeMap(GLuint Texture)
{
if (mTextureCubeMap == Texture)
@ -529,210 +660,6 @@ void lcContext::SetInterfaceColor(lcInterfaceColor InterfaceColor)
SetColor(gInterfaceColors[InterfaceColor]);
}
void lcContext::ClearFramebuffer()
{
if (!mFramebufferObject)
return;
if (gSupportsFramebufferObjectARB)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
#ifndef LC_OPENGLES
else if (gSupportsFramebufferObjectEXT)
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
#endif
mFramebufferObject = 0;
}
lcFramebuffer lcContext::CreateFramebuffer(int Width, int Height, bool Depth, bool Multisample)
{
lcFramebuffer Framebuffer(Width, Height);
if (gSupportsFramebufferObjectARB)
{
int Samples = (Multisample && gSupportsTexImage2DMultisample && QGLFormat::defaultFormat().sampleBuffers()) ? QGLFormat::defaultFormat().samples() : 1;
glGenFramebuffers(1, &Framebuffer.mObject);
glBindFramebuffer(GL_FRAMEBUFFER, Framebuffer.mObject);
glGenTextures(1, &Framebuffer.mColorTexture);
if (Depth)
glGenRenderbuffers(1, &Framebuffer.mDepthRenderbuffer);
if (Samples == 1)
{
BindTexture2D(Framebuffer.mColorTexture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
BindTexture2D(0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Framebuffer.mColorTexture, 0);
if (Depth)
{
glBindRenderbuffer(GL_RENDERBUFFER, Framebuffer.mDepthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, Width, Height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, Framebuffer.mDepthRenderbuffer);
}
}
#ifndef LC_OPENGLES
else
{
BindTexture2DMS(Framebuffer.mColorTexture);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, Samples, GL_RGBA, Width, Height, GL_TRUE);
BindTexture2DMS(0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, Framebuffer.mColorTexture, 0);
if (Depth)
{
glBindRenderbuffer(GL_RENDERBUFFER, Framebuffer.mDepthRenderbuffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, Samples, GL_DEPTH_COMPONENT24, Width, Height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, Framebuffer.mDepthRenderbuffer);
}
}
#endif
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
DestroyFramebuffer(Framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferObject);
}
#ifndef LC_OPENGLES
else if (gSupportsFramebufferObjectEXT)
{
glGenFramebuffersEXT(1, &Framebuffer.mObject);
glGenTextures(1, &Framebuffer.mColorTexture);
BindTexture2D(Framebuffer.mColorTexture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Framebuffer.mObject);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, Framebuffer.mColorTexture, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Framebuffer.mObject);
glGenRenderbuffersEXT(1, &Framebuffer.mDepthRenderbuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, Framebuffer.mDepthRenderbuffer);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, Width, Height);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, Framebuffer.mDepthRenderbuffer);
BindTexture2D(0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Framebuffer.mObject);
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
DestroyFramebuffer(Framebuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebufferObject);
}
#endif
return Framebuffer;
}
void lcContext::DestroyFramebuffer(lcFramebuffer& Framebuffer)
{
if (gSupportsFramebufferObjectARB)
{
glDeleteFramebuffers(1, &Framebuffer.mObject);
glDeleteTextures(1, &Framebuffer.mColorTexture);
glDeleteRenderbuffers(1, &Framebuffer.mDepthRenderbuffer);
}
#ifndef LC_OPENGLES
else if (gSupportsFramebufferObjectEXT)
{
glDeleteFramebuffersEXT(1, &Framebuffer.mObject);
glDeleteTextures(1, &Framebuffer.mColorTexture);
glDeleteRenderbuffersEXT(1, &Framebuffer.mDepthRenderbuffer);
}
#endif
Framebuffer.mObject = 0;
Framebuffer.mColorTexture = 0;
Framebuffer.mDepthRenderbuffer = 0;
Framebuffer.mWidth = 0;
Framebuffer.mHeight = 0;
}
void lcContext::BindFramebuffer(GLuint FramebufferObject)
{
if (FramebufferObject == mFramebufferObject)
return;
if (gSupportsFramebufferObjectARB)
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferObject);
#ifndef LC_OPENGLES
else if (gSupportsFramebufferObjectEXT)
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferObject);
#endif
mFramebufferObject = FramebufferObject;
}
std::pair<lcFramebuffer, lcFramebuffer> lcContext::CreateRenderFramebuffer(int Width, int Height)
{
if (gSupportsFramebufferObjectARB && QGLFormat::defaultFormat().sampleBuffers() && QGLFormat::defaultFormat().samples() > 1)
return std::make_pair(CreateFramebuffer(Width, Height, true, true), CreateFramebuffer(Width, Height, false, false));
else
return std::make_pair(CreateFramebuffer(Width, Height, true, false), lcFramebuffer());
}
void lcContext::DestroyRenderFramebuffer(std::pair<lcFramebuffer, lcFramebuffer>& RenderFramebuffer)
{
DestroyFramebuffer(RenderFramebuffer.first);
DestroyFramebuffer(RenderFramebuffer.second);
}
QImage lcContext::GetRenderFramebufferImage(const std::pair<lcFramebuffer, lcFramebuffer>& RenderFramebuffer)
{
QImage Image(RenderFramebuffer.first.mWidth, RenderFramebuffer.first.mHeight, QImage::Format_ARGB32);
GetRenderFramebufferImage(RenderFramebuffer, Image.bits());
return Image;
}
void lcContext::GetRenderFramebufferImage(const std::pair<lcFramebuffer, lcFramebuffer>& RenderFramebuffer, quint8* Buffer)
{
const int Width = RenderFramebuffer.first.mWidth;
const int Height = RenderFramebuffer.first.mHeight;
const GLuint SavedFramebuffer = mFramebufferObject;
if (RenderFramebuffer.second.IsValid())
{
#ifndef LC_OPENGLES
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, RenderFramebuffer.second.mObject);
glBindFramebuffer(GL_READ_FRAMEBUFFER, RenderFramebuffer.first.mObject);
glBlitFramebuffer(0, 0, Width, Height, 0, 0, Width, Height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
BindFramebuffer(RenderFramebuffer.second);
#endif
}
else
BindFramebuffer(RenderFramebuffer.first);
glFinish();
glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, Buffer);
BindFramebuffer(SavedFramebuffer);
for (int y = 0; y < (Height + 1) / 2; y++)
{
quint8* Top = Buffer + ((Height - y - 1) * Width * 4);
quint8* Bottom = Buffer + y * Width * 4;
for (int x = 0; x < Width; x++)
{
QRgb TopColor = qRgba(Top[0], Top[1], Top[2], Top[3]);
QRgb BottomColor = qRgba(Bottom[0], Bottom[1], Bottom[2], Bottom[3]);
*(QRgb*)Top = BottomColor;
*(QRgb*)Bottom = TopColor;
Top += 4;
Bottom += 4;
}
}
}
lcVertexBuffer lcContext::CreateVertexBuffer(int Size, const void* Data)
{
lcVertexBuffer VertexBuffer;
@ -966,7 +893,7 @@ void lcContext::SetVertexFormatPosition(int PositionSize)
void lcContext::SetVertexFormat(int BufferOffset, int PositionSize, int NormalSize, int TexCoordSize, int ColorSize, bool EnableNormals)
{
const int VertexSize = (PositionSize + TexCoordSize + ColorSize) * sizeof(float) + NormalSize * sizeof(quint32);
const int VertexSize = (PositionSize + TexCoordSize) * sizeof(float) + NormalSize * sizeof(quint32) + ColorSize;
char* VertexBufferPointer = mVertexBufferPointer + BufferOffset;
if (gSupportsShaderObjects)
@ -1017,7 +944,7 @@ void lcContext::SetVertexFormat(int BufferOffset, int PositionSize, int NormalSi
if (ColorSize)
{
glVertexAttribPointer(LC_ATTRIB_COLOR, ColorSize, GL_FLOAT, false, VertexSize, VertexBufferPointer + Offset);
glVertexAttribPointer(LC_ATTRIB_COLOR, ColorSize, GL_UNSIGNED_BYTE, true, VertexSize, VertexBufferPointer + Offset);
if (!mColorEnabled)
{
@ -1229,10 +1156,7 @@ void lcContext::FlushState()
if (mHighlightParamsDirty && Program.HighlightParamsLocation != -1)
{
lcMatrix44 InverseViewMatrix = lcMatrix44AffineInverse(mViewMatrix);
mHighlightParams[4] = InverseViewMatrix[2];
glUniform4fv(Program.HighlightParamsLocation, 5, mHighlightParams[0]);
glUniform4fv(Program.HighlightParamsLocation, 4, mHighlightParams[0]);
mHighlightParamsDirty = false;
}
}

View file

@ -76,30 +76,6 @@ struct lcProgram
GLint HighlightParamsLocation;
};
class lcFramebuffer
{
public:
lcFramebuffer()
{
}
lcFramebuffer(int Width, int Height)
: mWidth(Width), mHeight(Height)
{
}
bool IsValid() const
{
return mObject != 0;
}
GLuint mObject = 0;
GLuint mColorTexture = 0;
GLuint mDepthRenderbuffer = 0;
int mWidth = 0;
int mHeight = 0;
};
enum class lcPolygonOffset
{
None,
@ -107,23 +83,38 @@ enum class lcPolygonOffset
Translucent
};
class lcContext
enum class lcDepthFunction
{
LessEqual,
Always
};
class lcContext : protected QOpenGLFunctions
{
public:
lcContext();
~lcContext();
lcContext(const lcContext&) = delete;
lcContext(lcContext&&) = delete;
lcContext& operator=(const lcContext&) = delete;
lcContext& operator=(lcContext&&) = delete;
static void CreateResources();
static void DestroyResources();
static bool CreateOffscreenContext();
static void DestroyOffscreenContext();
void CreateResources();
void DestroyResources();
void SetDefaultState();
void ClearResources();
void MakeCurrent();
void SetGLContext(QOpenGLContext* GLContext, QOpenGLWidget* Widget);
void SetOffscreenContext();
void ClearColorAndDepth(const lcVector4& ClearColor);
void ClearDepth();
void SetWorldMatrix(const lcMatrix44& WorldMatrix)
{
mWorldMatrix = WorldMatrix;
@ -153,10 +144,11 @@ public:
void SetViewport(int x, int y, int Width, int Height);
void SetPolygonOffset(lcPolygonOffset PolygonOffset);
void SetDepthWrite(bool Enable);
void SetDepthFunction(lcDepthFunction DepthFunction);
void EnableCullFace(bool Enable);
void SetLineWidth(float LineWidth);
void SetSmoothShading(bool Smooth);
void BindTexture2D(GLuint Texture);
void BindTexture2DMS(GLuint Texture);
void BindTextureCubeMap(GLuint Texture);
void UnbindTexture2D(GLuint Texture);
void UnbindTextureCubeMap(GLuint Texture);
@ -184,20 +176,6 @@ public:
void SetEdgeColorIndexTinted(int ColorIndex, const lcVector4& Tint);
void SetInterfaceColor(lcInterfaceColor InterfaceColor);
void ClearFramebuffer();
lcFramebuffer CreateFramebuffer(int Width, int Height, bool Depth, bool Multisample);
void DestroyFramebuffer(lcFramebuffer& Framebuffer);
void BindFramebuffer(GLuint FramebufferObject);
void BindFramebuffer(const lcFramebuffer& Framebuffer)
{
BindFramebuffer(Framebuffer.mObject);
}
std::pair<lcFramebuffer, lcFramebuffer> CreateRenderFramebuffer(int Width, int Height);
void DestroyRenderFramebuffer(std::pair<lcFramebuffer, lcFramebuffer>& RenderFramebuffer);
QImage GetRenderFramebufferImage(const std::pair<lcFramebuffer, lcFramebuffer>& RenderFramebuffer);
void GetRenderFramebufferImage(const std::pair<lcFramebuffer, lcFramebuffer>& RenderFramebuffer, quint8* Buffer);
lcVertexBuffer CreateVertexBuffer(int Size, const void* Data);
void DestroyVertexBuffer(lcVertexBuffer& VertexBuffer);
lcIndexBuffer CreateIndexBuffer(int Size, const void* Data);
@ -219,9 +197,13 @@ public:
void BindMesh(const lcMesh* Mesh);
protected:
static void CreateShaderPrograms();
void CreateShaderPrograms();
void FlushState();
QOpenGLWidget* mWidget = nullptr;
QOpenGLContext* mContext = nullptr;
bool mValid = false;
GLuint mVertexBufferObject;
GLuint mIndexBufferObject;
char* mVertexBufferPointer;
@ -234,10 +216,11 @@ protected:
bool mColorEnabled;
GLuint mTexture2D;
GLuint mTexture2DMS;
GLuint mTextureCubeMap;
lcPolygonOffset mPolygonOffset;
bool mDepthWrite;
lcDepthFunction mDepthFunction;
bool mCullFace;
float mLineWidth;
int mMatrixMode;
bool mTextureEnabled;
@ -247,7 +230,7 @@ protected:
lcMatrix44 mViewMatrix;
lcMatrix44 mProjectionMatrix;
lcMatrix44 mViewProjectionMatrix;
lcVector4 mHighlightParams[5];
lcVector4 mHighlightParams[4];
bool mColorDirty;
bool mWorldMatrixDirty;
bool mViewMatrixDirty;
@ -255,9 +238,11 @@ protected:
bool mViewProjectionMatrixDirty;
bool mHighlightParamsDirty;
GLuint mFramebufferObject;
static std::unique_ptr<QOpenGLContext> mOffscreenContext;
static std::unique_ptr<QOffscreenSurface> mOffscreenSurface;
static lcProgram mPrograms[static_cast<int>(lcMaterialType::Count)];
static int mValidContexts;
Q_DECLARE_TR_FUNCTIONS(lcContext);
};

View file

@ -0,0 +1,270 @@
#include "lc_edgecolordialog.h"
#include "lc_application.h"
lcAutomateEdgeColorDialog::lcAutomateEdgeColorDialog(QWidget* Parent, bool ShowHighContrastDialog)
:QDialog(Parent)
{
const lcPreferences& Preferences = lcGetPreferences();
mStudCylinderColor = Preferences.mStudCylinderColor;
mPartEdgeColor = Preferences.mPartEdgeColor;
mBlackEdgeColor = Preferences.mBlackEdgeColor;
mDarkEdgeColor = Preferences.mDarkEdgeColor;
mPartEdgeContrast = Preferences.mPartEdgeContrast;
mPartColorValueLDIndex = Preferences.mPartColorValueLDIndex;
setWindowTitle(tr("Color Preferences"));
QVBoxLayout* MainLayout = new QVBoxLayout(this);
QGroupBox* EdgeSettingsBox = new QGroupBox(tr("Edge Colors"), this);
MainLayout->addWidget(EdgeSettingsBox);
QGridLayout* EdgeSettingsLayout = new QGridLayout(EdgeSettingsBox);
EdgeSettingsBox->setLayout(EdgeSettingsLayout);
int LDIndexRow = 0;
PartEdgeContrast = nullptr;
PartEdgeContrastSlider = nullptr;
if (!ShowHighContrastDialog)
{
LDIndexRow = 1;
QLabel* PartEdgeContrastLabel = new QLabel(tr("Contrast:"), this);
PartEdgeContrast = new QLabel(this);
PartEdgeContrastSlider = new QSlider(Qt::Horizontal, this);
PartEdgeContrastSlider->setRange(0, 100);
PartEdgeContrastSlider->setValue(mPartEdgeContrast * 100);
PartEdgeContrastSlider->setToolTip(tr("Set the amount of contrast - 0.50 is midway."));
connect(PartEdgeContrastSlider, SIGNAL(valueChanged(int)), this, SLOT(SliderValueChanged(int)));
emit PartEdgeContrastSlider->valueChanged(PartEdgeContrastSlider->value());
ResetPartEdgeContrastButton = new QToolButton(this);
ResetPartEdgeContrastButton->setText(tr("Reset"));
connect(ResetPartEdgeContrastButton, SIGNAL(clicked()), this, SLOT(ResetSliderButtonClicked()));
EdgeSettingsLayout->addWidget(PartEdgeContrastLabel,0,0);
EdgeSettingsLayout->addWidget(PartEdgeContrastSlider,0,1);
EdgeSettingsLayout->addWidget(PartEdgeContrast,0,2);
EdgeSettingsLayout->addWidget(ResetPartEdgeContrastButton,0,3);
}
QLabel* PartColorValueLDIndexLabel = new QLabel(tr(ShowHighContrastDialog ? "Light/Dark Value:" : "Saturation:"), this);
PartColorValueLDIndex = new QLabel(this);
PartColorValueLDIndexSlider = new QSlider(Qt::Horizontal, this);
PartColorValueLDIndexSlider->setRange(0, 100);
PartColorValueLDIndexSlider->setValue(mPartColorValueLDIndex * 100);
PartColorValueLDIndexSlider->setToolTip(tr(ShowHighContrastDialog ?
"Set to classify where color values are light or dark - e.g. Dark Bluish Gray (72) is light at 0.39." :
"Set to specify amount of edge color tint or shade from the saturation adjusted part color"));
connect(PartColorValueLDIndexSlider, SIGNAL(valueChanged(int)), this, SLOT(SliderValueChanged(int)));
emit PartColorValueLDIndexSlider->valueChanged(PartColorValueLDIndexSlider->value());
ResetPartColorValueLDIndexButton = new QToolButton(this);
ResetPartColorValueLDIndexButton->setText(tr("Reset"));
connect(ResetPartColorValueLDIndexButton, SIGNAL(clicked()), this, SLOT(ResetSliderButtonClicked()));
EdgeSettingsLayout->addWidget(PartColorValueLDIndexLabel,LDIndexRow,0);
EdgeSettingsLayout->addWidget(PartColorValueLDIndexSlider,LDIndexRow,1);
EdgeSettingsLayout->addWidget(PartColorValueLDIndex,LDIndexRow,2);
EdgeSettingsLayout->addWidget(ResetPartColorValueLDIndexButton,LDIndexRow,3);
QGroupBox* HighContrastColorBox = new QGroupBox(tr("High Contrast"), this);
HighContrastColorBox->setVisible(ShowHighContrastDialog);
MainLayout->addWidget(HighContrastColorBox);
QGridLayout* HighContrastColorLayout = new QGridLayout(HighContrastColorBox);
HighContrastColorBox->setLayout(HighContrastColorLayout);
auto SetButtonPixmap = [](quint32 Color, QToolButton* Button)
{
QPixmap Pixmap(12, 12);
QColor ButtonColor(QColor(LC_RGBA_RED(Color), LC_RGBA_GREEN(Color), LC_RGBA_BLUE(Color)));
Pixmap.fill(ButtonColor);
Button->setIcon(Pixmap);
Button->setToolTip(ButtonColor.name().toUpper());
};
QLabel* StudCylinderColorLabel = new QLabel(tr("Stud Cylinder Color:"), this);
StudCylinderColorButton = new QToolButton(this);
SetButtonPixmap(mStudCylinderColor, StudCylinderColorButton);
connect(StudCylinderColorButton, SIGNAL(clicked()), this, SLOT(ColorButtonClicked()));
ResetStudCylinderColorButton = new QToolButton(this);
ResetStudCylinderColorButton->setText(tr("Reset"));;
connect(ResetStudCylinderColorButton, SIGNAL(clicked()), this, SLOT(ResetColorButtonClicked()));
HighContrastColorLayout->addWidget(StudCylinderColorLabel,0,0);
HighContrastColorLayout->addWidget(StudCylinderColorButton,0,1);
HighContrastColorLayout->addWidget(ResetStudCylinderColorButton,0,2);
QLabel* PartEdgeColorLabel = new QLabel(tr("Parts Edge Color:"), this);
PartEdgeColorButton = new QToolButton(this);
SetButtonPixmap(mPartEdgeColor, PartEdgeColorButton);
connect(PartEdgeColorButton, SIGNAL(clicked()), this, SLOT(ColorButtonClicked()));
ResetPartEdgeColorButton = new QToolButton(this);
ResetPartEdgeColorButton->setText(tr("Reset"));
connect(ResetPartEdgeColorButton, SIGNAL(clicked()), this, SLOT(ResetColorButtonClicked()));
HighContrastColorLayout->addWidget(PartEdgeColorLabel,1,0);
HighContrastColorLayout->addWidget(PartEdgeColorButton,1,1);
HighContrastColorLayout->addWidget(ResetPartEdgeColorButton,1,2);
QLabel* BlackEdgeColorLabel = new QLabel(tr("Black Parts Edge Color:"), this);
BlackEdgeColorButton = new QToolButton(this);
SetButtonPixmap(mBlackEdgeColor, BlackEdgeColorButton);
connect(BlackEdgeColorButton, SIGNAL(clicked()), this, SLOT(ColorButtonClicked()));
ResetBlackEdgeColorButton = new QToolButton(this);
ResetBlackEdgeColorButton->setText(tr("Reset"));
connect(ResetBlackEdgeColorButton, SIGNAL(clicked()), this, SLOT(ResetColorButtonClicked()));
HighContrastColorLayout->addWidget(BlackEdgeColorLabel,2,0);
HighContrastColorLayout->addWidget(BlackEdgeColorButton,2,1);
HighContrastColorLayout->addWidget(ResetBlackEdgeColorButton,2,2);
QLabel* DarkEdgeColorLabel = new QLabel(tr("Dark Parts Edge Color:"), this);
DarkEdgeColorButton = new QToolButton(this);
SetButtonPixmap(mDarkEdgeColor, DarkEdgeColorButton);
connect(DarkEdgeColorButton, SIGNAL(clicked()), this, SLOT(ColorButtonClicked()));
ResetDarkEdgeColorButton = new QToolButton(this);
ResetDarkEdgeColorButton->setText(tr("Reset"));
connect(ResetDarkEdgeColorButton, SIGNAL(clicked()), this, SLOT(ResetColorButtonClicked()));
HighContrastColorLayout->addWidget(DarkEdgeColorLabel,3,0);
HighContrastColorLayout->addWidget(DarkEdgeColorButton,3,1);
HighContrastColorLayout->addWidget(ResetDarkEdgeColorButton,3,2);
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
MainLayout->addWidget(buttonBox);
QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
setMinimumSize(220,100);
}
void lcAutomateEdgeColorDialog::SliderValueChanged(int Value)
{
if (sender() == PartEdgeContrastSlider)
{
mPartEdgeContrast = Value * 0.01f;
PartEdgeContrast->setText(QString::number(mPartEdgeContrast, 'f', 2));
}
else if (sender() == PartColorValueLDIndexSlider)
{
mPartColorValueLDIndex = Value * 0.01f;
PartColorValueLDIndex->setText(QString::number(mPartColorValueLDIndex, 'f', 2));
}
}
void lcAutomateEdgeColorDialog::ColorButtonClicked()
{
QObject* Button = sender();
QString Title;
quint32* Color = nullptr;
QColorDialog::ColorDialogOptions DialogOptions;
if (Button == StudCylinderColorButton)
{
Title = tr("Select Stud Cylinder Color");
Color = &mStudCylinderColor;
}
else if (Button == PartEdgeColorButton)
{
Title = tr("Select Part Edge Color");
Color = &mPartEdgeColor;
}
else if (Button == BlackEdgeColorButton)
{
if (lcGetPreferences().mAutomateEdgeColor)
{
QMessageBox msgBox;
msgBox.setText("Automate edge color appears to be enabled.<br>Black parts edge color will not be accessible.<br>Do you want to continue ?");
if (msgBox.exec() != QMessageBox::Accepted)
return;
}
Title = tr("Select Black Edge Color");
Color = &mBlackEdgeColor;
}
else if (Button == DarkEdgeColorButton)
{
if (lcGetPreferences().mAutomateEdgeColor)
{
QMessageBox msgBox;
msgBox.setText("Automate edge color appears to be enabled.<br>Dark parts edge color will not be accessible.<br>Do you want to continue ?");
if (msgBox.exec() != QMessageBox::Accepted)
return;
}
Title = tr("Select Dark Edge Color");
Color = &mDarkEdgeColor;
}
else
return;
QColor OldColor = QColor(LC_RGBA_RED(*Color), LC_RGBA_GREEN(*Color), LC_RGBA_BLUE(*Color), LC_RGBA_ALPHA(*Color));
QColor NewColor = QColorDialog::getColor(OldColor, this, Title, DialogOptions);
if (NewColor == OldColor || !NewColor.isValid())
return;
*Color = LC_RGBA(NewColor.red(), NewColor.green(), NewColor.blue(), NewColor.alpha());
QPixmap Pix(12, 12);
NewColor.setAlpha(255);
Pix.fill(NewColor);
((QToolButton*)Button)->setIcon(Pix);
((QToolButton*)Button)->setToolTip(NewColor.name().toUpper());
}
void lcAutomateEdgeColorDialog::ResetSliderButtonClicked()
{
if (sender() == ResetPartEdgeContrastButton)
{
PartEdgeContrastSlider->setValue(0.5f * 100);
}
else if (sender() == ResetPartColorValueLDIndexButton)
{
PartColorValueLDIndexSlider->setValue(0.5f * 100);
}
}
void lcAutomateEdgeColorDialog::ResetColorButtonClicked()
{
quint32* Color = nullptr;
QPixmap Pix(12, 12);
QColor ResetColor;
if (sender() == ResetStudCylinderColorButton)
{
Color = &mStudCylinderColor;
*Color = LC_RGBA(27, 42, 52, 255);
ResetColor = QColor(LC_RGBA_RED(*Color), LC_RGBA_GREEN(*Color), LC_RGBA_BLUE(*Color), LC_RGBA_ALPHA(*Color));
Pix.fill(ResetColor);
StudCylinderColorButton->setIcon(Pix);
StudCylinderColorButton->setToolTip(ResetColor.name().toUpper());
}
else if (sender() == ResetPartEdgeColorButton)
{
Color = &mPartEdgeColor;
*Color = LC_RGBA(0, 0, 0, 255);
ResetColor = QColor(LC_RGBA_RED(*Color), LC_RGBA_GREEN(*Color), LC_RGBA_BLUE(*Color), LC_RGBA_ALPHA(*Color));
Pix.fill(ResetColor);
PartEdgeColorButton->setIcon(Pix);
PartEdgeColorButton->setToolTip(ResetColor.name().toUpper());
}
else if (sender() == ResetBlackEdgeColorButton)
{
Color = &mBlackEdgeColor;
*Color = LC_RGBA(255, 255, 255, 255);
ResetColor = QColor(LC_RGBA_RED(*Color), LC_RGBA_GREEN(*Color), LC_RGBA_BLUE(*Color), LC_RGBA_ALPHA(*Color));
Pix.fill(ResetColor);
BlackEdgeColorButton->setIcon(Pix);
BlackEdgeColorButton->setToolTip(ResetColor.name().toUpper());
}
else if (sender() == ResetDarkEdgeColorButton)
{
Color = &mDarkEdgeColor;
*Color = LC_RGBA(27, 42, 52, 255);
ResetColor = QColor(LC_RGBA_RED(*Color), LC_RGBA_GREEN(*Color), LC_RGBA_BLUE(*Color), LC_RGBA_ALPHA(*Color));
Pix.fill(ResetColor);
DarkEdgeColorButton->setIcon(Pix);
DarkEdgeColorButton->setToolTip(ResetColor.name().toUpper());
}
}

View file

@ -0,0 +1,43 @@
#pragma once
#include <QtWidgets>
class lcAutomateEdgeColorDialog : public QDialog
{
Q_OBJECT
public:
lcAutomateEdgeColorDialog(QWidget *Parent, bool ShowHighContrastDialog);
quint32 mStudCylinderColor;
quint32 mPartEdgeColor;
quint32 mDarkEdgeColor;
quint32 mBlackEdgeColor;
float mPartEdgeContrast;
float mPartColorValueLDIndex;
protected slots:
void SliderValueChanged(int);
void ResetSliderButtonClicked();
void ColorButtonClicked();
void ResetColorButtonClicked();
protected:
QSlider* PartColorValueLDIndexSlider;
QSlider* PartEdgeContrastSlider;
QLabel* PartEdgeContrast;
QLabel* PartColorValueLDIndex;
QToolButton* ResetPartEdgeContrastButton;
QToolButton* ResetPartColorValueLDIndexButton;
QToolButton* StudCylinderColorButton;
QToolButton* PartEdgeColorButton;
QToolButton* BlackEdgeColorButton;
QToolButton* DarkEdgeColorButton;
QToolButton* ResetStudCylinderColorButton;
QToolButton* ResetPartEdgeColorButton;
QToolButton* ResetBlackEdgeColorButton;
QToolButton* ResetDarkEdgeColorButton;
};

View file

@ -0,0 +1,164 @@
#include "lc_global.h"
#include "lc_findreplacewidget.h"
#include "lc_qcolorpicker.h"
#include "lc_library.h"
#include "lc_mainwindow.h"
#include "pieceinf.h"
#include "piece.h"
#include "lc_model.h"
#include "lc_view.h"
lcFindReplaceWidget::lcFindReplaceWidget(QWidget* Parent, lcModel* Model, bool Replace)
: QWidget(Parent)
{
setAutoFillBackground(true);
QPalette Palette = palette();
Palette.setColor(QPalette::Window, QApplication::palette().color(QPalette::Button));
setPalette(Palette);
QGridLayout* Layout = new QGridLayout(this);
Layout->setContentsMargins(5, 5, 5, 5);
Layout->addWidget(new QLabel(tr("Find:")), 0, 0);
lcQColorPicker* FindColorPicker = new lcQColorPicker(this, true);
Layout->addWidget(FindColorPicker, 0, 1);
mFindPartComboBox = new QComboBox(this);
mFindPartComboBox->setEditable(true);
mFindPartComboBox->setInsertPolicy(QComboBox::NoInsert);
Layout->addWidget(mFindPartComboBox, 0, 2);
QToolButton* FindNextButton = new QToolButton(this);
FindNextButton->setAutoRaise(true);
FindNextButton->setDefaultAction(gMainWindow->mActions[LC_EDIT_FIND_NEXT]);
Layout->addWidget(FindNextButton, 0, 3);
QToolButton* FindAllButton = new QToolButton(this);
FindAllButton ->setAutoRaise(true);
FindAllButton ->setDefaultAction(gMainWindow->mActions[LC_EDIT_FIND_ALL]);
Layout->addWidget(FindAllButton, 0, 4);
connect(FindColorPicker, &lcQColorPicker::colorChanged, this, &lcFindReplaceWidget::FindColorIndexChanged);
connect(mFindPartComboBox->lineEdit(), &QLineEdit::returnPressed, gMainWindow->mActions[LC_EDIT_FIND_NEXT], &QAction::trigger);
connect(mFindPartComboBox->lineEdit(), &QLineEdit::textEdited, this, &lcFindReplaceWidget::FindTextEdited);
connect(mFindPartComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &lcFindReplaceWidget::FindActivated);
lcQColorPicker* ReplaceColorPicker = nullptr;
if (Replace)
{
Layout->addWidget(new QLabel(tr("Replace:")), 1, 0);
ReplaceColorPicker = new lcQColorPicker(this, true);
Layout->addWidget(ReplaceColorPicker, 1, 1);
mReplacePartComboBox = new QComboBox(this);
Layout->addWidget(mReplacePartComboBox, 1, 2);
QToolButton* ReplaceNextButton = new QToolButton(this);
ReplaceNextButton->setAutoRaise(true);
ReplaceNextButton->setDefaultAction(gMainWindow->mActions[LC_EDIT_REPLACE_NEXT]);
Layout->addWidget(ReplaceNextButton, 1, 3);
QToolButton* ReplaceAllButton = new QToolButton(this);
ReplaceAllButton->setAutoRaise(true);
ReplaceAllButton->setDefaultAction(gMainWindow->mActions[LC_EDIT_REPLACE_ALL]);
Layout->addWidget(ReplaceAllButton, 1, 4);
connect(ReplaceColorPicker, &lcQColorPicker::colorChanged, this, &lcFindReplaceWidget::ReplaceColorIndexChanged);
connect(mReplacePartComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &lcFindReplaceWidget::ReplaceActivated);
mReplacePartComboBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
mReplacePartComboBox->setMinimumContentsLength(1);
lcPiecesLibrary* Library = lcGetPiecesLibrary();
std::vector<PieceInfo*> SortedPieces;
SortedPieces.reserve(Library->mPieces.size());
for (const auto& PartIt : Library->mPieces)
SortedPieces.push_back(PartIt.second);
auto PieceCompare = [](PieceInfo* Info1, PieceInfo* Info2)
{
return strcmp(Info1->m_strDescription, Info2->m_strDescription) < 0;
};
std::sort(SortedPieces.begin(), SortedPieces.end(), PieceCompare);
mReplacePartComboBox->addItem(QString(), QVariant::fromValue((void*)nullptr));
for (PieceInfo* Info : SortedPieces)
mReplacePartComboBox->addItem(QString::fromLatin1(Info->m_strDescription), QVariant::fromValue((void*)Info));
ReplaceColorPicker->setCurrentColor(lcGetColorIndex(LC_COLOR_NOCOLOR));
mReplacePartComboBox->setCurrentIndex(0);
}
lcPartsList PartsList;
Model->GetPartsList(gDefaultColor, false, true, PartsList);
for (const auto& PartIt : PartsList)
mFindPartComboBox->addItem(QString::fromLatin1(PartIt.first->m_strDescription), QVariant::fromValue((void*)PartIt.first));
mFindPartComboBox->model()->sort(0);
lcPiece* Focus = dynamic_cast<lcPiece*>(Model->GetFocusObject());
if (Focus)
{
lcFindReplaceParams& Params = lcView::GetFindReplaceParams();
Params.FindInfo = Focus->mPieceInfo;
Params.FindColorIndex = Focus->GetColorIndex();
FindColorPicker->setCurrentColor(Params.FindColorIndex);
mFindPartComboBox->setCurrentIndex(mFindPartComboBox->findData(QVariant::fromValue((void*)Params.FindInfo)));
}
else
{
FindColorPicker->setCurrentColor(lcGetColorIndex(LC_COLOR_NOCOLOR));
mFindPartComboBox->setEditText(QString());
}
mFindPartComboBox->setFocus();
adjustSize();
move(1, 1);
show();
}
void lcFindReplaceWidget::FindColorIndexChanged(int ColorIndex)
{
lcFindReplaceParams& Params = lcView::GetFindReplaceParams();
Params.FindColorIndex = ColorIndex;
}
void lcFindReplaceWidget::FindTextEdited(const QString& Text)
{
lcFindReplaceParams& Params = lcView::GetFindReplaceParams();
Params.FindString = Text;
Params.FindInfo = nullptr;
}
void lcFindReplaceWidget::FindActivated(int Index)
{
lcFindReplaceParams& Params = lcView::GetFindReplaceParams();
Params.FindString.clear();
Params.FindInfo = (PieceInfo*)mFindPartComboBox->itemData(Index).value<void*>();
}
void lcFindReplaceWidget::ReplaceColorIndexChanged(int ColorIndex)
{
lcFindReplaceParams& Params = lcView::GetFindReplaceParams();
Params.ReplaceColorIndex = ColorIndex;
}
void lcFindReplaceWidget::ReplaceActivated(int Index)
{
lcFindReplaceParams& Params = lcView::GetFindReplaceParams();
Params.ReplacePieceInfo = (PieceInfo*)mReplacePartComboBox->itemData(Index).value<void*>();
}

View file

@ -0,0 +1,20 @@
#pragma once
class lcFindReplaceWidget : public QWidget
{
Q_OBJECT
public:
lcFindReplaceWidget(QWidget* Parent, lcModel* Model, bool Replace);
protected slots:
void FindColorIndexChanged(int ColorIndex);
void FindTextEdited(const QString& Text);
void FindActivated(int Index);
void ReplaceColorIndexChanged(int ColorIndex);
void ReplaceActivated(int Index);
protected:
QComboBox* mFindPartComboBox = nullptr;
QComboBox* mReplacePartComboBox = nullptr;
};

File diff suppressed because it is too large Load diff

View file

@ -1,157 +1,14 @@
#include "lc_global.h"
#include "lc_glextensions.h"
#include <QOpenGLFunctions_3_2_Core>
bool gSupportsShaderObjects;
bool gSupportsVertexBufferObject;
bool gSupportsFramebufferObjectARB;
bool gSupportsFramebufferObjectEXT;
bool gSupportsTexImage2DMultisample;
bool gSupportsFramebufferObject;
bool gSupportsBlendFuncSeparate;
bool gSupportsAnisotropic;
GLfloat gMaxAnisotropy;
#ifdef LC_LOAD_GLEXTENSIONS
PFNGLBINDBUFFERARBPROC lcBindBufferARB;
PFNGLDELETEBUFFERSARBPROC lcDeleteBuffersARB;
PFNGLGENBUFFERSARBPROC lcGenBuffersARB;
PFNGLISBUFFERARBPROC lcIsBufferARB;
PFNGLBUFFERDATAARBPROC lcBufferDataARB;
PFNGLBUFFERSUBDATAARBPROC lcBufferSubDataARB;
PFNGLGETBUFFERSUBDATAARBPROC lcGetBufferSubDataARB;
PFNGLMAPBUFFERARBPROC lcMapBufferARB;
PFNGLUNMAPBUFFERARBPROC lcUnmapBufferARB;
PFNGLGETBUFFERPARAMETERIVARBPROC lcGetBufferParameterivARB;
PFNGLGETBUFFERPOINTERVARBPROC lcGetBufferPointervARB;
PFNGLISRENDERBUFFERPROC lcIsRenderbuffer;
PFNGLBINDRENDERBUFFERPROC lcBindRenderbuffer;
PFNGLDELETERENDERBUFFERSPROC lcDeleteRenderbuffers;
PFNGLGENRENDERBUFFERSPROC lcGenRenderbuffers;
PFNGLRENDERBUFFERSTORAGEPROC lcRenderbufferStorage;
PFNGLGETRENDERBUFFERPARAMETERIVPROC lcGetRenderbufferParameteriv;
PFNGLISFRAMEBUFFERPROC lcIsFramebuffer;
PFNGLBINDFRAMEBUFFERPROC lcBindFramebuffer;
PFNGLDELETEFRAMEBUFFERSPROC lcDeleteFramebuffers;
PFNGLGENFRAMEBUFFERSPROC lcGenFramebuffers;
PFNGLCHECKFRAMEBUFFERSTATUSPROC lcCheckFramebufferStatus;
PFNGLFRAMEBUFFERTEXTURE1DPROC lcFramebufferTexture1D;
PFNGLFRAMEBUFFERTEXTURE2DPROC lcFramebufferTexture2D;
PFNGLFRAMEBUFFERTEXTURE3DPROC lcFramebufferTexture3D;
PFNGLFRAMEBUFFERRENDERBUFFERPROC lcFramebufferRenderbuffer;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC lcGetFramebufferAttachmentParameteriv;
PFNGLGENERATEMIPMAPPROC lcGenerateMipmap;
PFNGLBLITFRAMEBUFFERPROC lcBlitFramebuffer;
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC lcRenderbufferStorageMultisample;
PFNGLFRAMEBUFFERTEXTURELAYERPROC lcFramebufferTextureLayer;
PFNGLISRENDERBUFFEREXTPROC lcIsRenderbufferEXT;
PFNGLBINDRENDERBUFFEREXTPROC lcBindRenderbufferEXT;
PFNGLDELETERENDERBUFFERSEXTPROC lcDeleteRenderbuffersEXT;
PFNGLGENRENDERBUFFERSEXTPROC lcGenRenderbuffersEXT;
PFNGLRENDERBUFFERSTORAGEEXTPROC lcRenderbufferStorageEXT;
PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC lcGetRenderbufferParameterivEXT;
PFNGLISFRAMEBUFFEREXTPROC lcIsFramebufferEXT;
PFNGLBINDFRAMEBUFFEREXTPROC lcBindFramebufferEXT;
PFNGLDELETEFRAMEBUFFERSEXTPROC lcDeleteFramebuffersEXT;
PFNGLGENFRAMEBUFFERSEXTPROC lcGenFramebuffersEXT;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC lcCheckFramebufferStatusEXT;
PFNGLFRAMEBUFFERTEXTURE1DEXTPROC lcFramebufferTexture1DEXT;
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC lcFramebufferTexture2DEXT;
PFNGLFRAMEBUFFERTEXTURE3DEXTPROC lcFramebufferTexture3DEXT;
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC lcFramebufferRenderbufferEXT;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC lcGetFramebufferAttachmentParameterivEXT;
PFNGLGENERATEMIPMAPEXTPROC lcGenerateMipmapEXT;
PFNGLATTACHSHADERPROC lcAttachShader;
PFNGLBINDATTRIBLOCATIONPROC lcBindAttribLocation;
PFNGLCOMPILESHADERPROC lcCompileShader;
PFNGLCREATEPROGRAMPROC lcCreateProgram;
PFNGLCREATESHADERPROC lcCreateShader;
PFNGLDELETEPROGRAMPROC lcDeleteProgram;
PFNGLDELETESHADERPROC lcDeleteShader;
PFNGLDETACHSHADERPROC lcDetachShader;
PFNGLDISABLEVERTEXATTRIBARRAYPROC lcDisableVertexAttribArray;
PFNGLENABLEVERTEXATTRIBARRAYPROC lcEnableVertexAttribArray;
PFNGLGETACTIVEATTRIBPROC lcGetActiveAttrib;
PFNGLGETACTIVEUNIFORMPROC lcGetActiveUniform;
PFNGLGETATTACHEDSHADERSPROC lcGetAttachedShaders;
PFNGLGETATTRIBLOCATIONPROC lcGetAttribLocation;
PFNGLGETPROGRAMIVPROC lcGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC lcGetProgramInfoLog;
PFNGLGETSHADERIVPROC lcGetShaderiv;
PFNGLGETSHADERINFOLOGPROC lcGetShaderInfoLog;
PFNGLGETSHADERSOURCEPROC lcGetShaderSource;
PFNGLGETUNIFORMLOCATIONPROC lcGetUniformLocation;
PFNGLGETUNIFORMFVPROC lcGetUniformfv;
PFNGLGETUNIFORMIVPROC lcGetUniformiv;
PFNGLGETVERTEXATTRIBDVPROC lcGetVertexAttribdv;
PFNGLGETVERTEXATTRIBFVPROC lcGetVertexAttribfv;
PFNGLGETVERTEXATTRIBIVPROC lcGetVertexAttribiv;
PFNGLGETVERTEXATTRIBPOINTERVPROC lcGetVertexAttribPointerv;
PFNGLISPROGRAMPROC lcIsProgram;
PFNGLISSHADERPROC lcIsShader;
PFNGLLINKPROGRAMPROC lcLinkProgram;
PFNGLSHADERSOURCEPROC lcShaderSource;
PFNGLUSEPROGRAMPROC lcUseProgram;
PFNGLUNIFORM1FPROC lcUniform1f;
PFNGLUNIFORM2FPROC lcUniform2f;
PFNGLUNIFORM3FPROC lcUniform3f;
PFNGLUNIFORM4FPROC lcUniform4f;
PFNGLUNIFORM1IPROC lcUniform1i;
PFNGLUNIFORM2IPROC lcUniform2i;
PFNGLUNIFORM3IPROC lcUniform3i;
PFNGLUNIFORM4IPROC lcUniform4i;
PFNGLUNIFORM1FVPROC lcUniform1fv;
PFNGLUNIFORM2FVPROC lcUniform2fv;
PFNGLUNIFORM3FVPROC lcUniform3fv;
PFNGLUNIFORM4FVPROC lcUniform4fv;
PFNGLUNIFORM1IVPROC lcUniform1iv;
PFNGLUNIFORM2IVPROC lcUniform2iv;
PFNGLUNIFORM3IVPROC lcUniform3iv;
PFNGLUNIFORM4IVPROC lcUniform4iv;
PFNGLUNIFORMMATRIX2FVPROC lcUniformMatrix2fv;
PFNGLUNIFORMMATRIX3FVPROC lcUniformMatrix3fv;
PFNGLUNIFORMMATRIX4FVPROC lcUniformMatrix4fv;
PFNGLVALIDATEPROGRAMPROC lcValidateProgram;
PFNGLVERTEXATTRIBPOINTERPROC lcVertexAttribPointer;
PFNGLTEXIMAGE2DMULTISAMPLEPROC lcTexImage2DMultisample;
PFNGLBLENDFUNCSEPARATEPROC lcBlendFuncSeparate;
#endif
static bool lcIsGLExtensionSupported(const GLubyte* Extensions, const char* Name)
{
const GLubyte* Start;
GLubyte* Where;
GLubyte* Terminator;
Where = (GLubyte*)strchr(Name, ' ');
if (Where || *Name == '\0')
return false;
if (!Extensions)
return false;
for (Start = Extensions; ;)
{
Where = (GLubyte*)strstr((const char*)Start, Name);
if (!Where)
break;
Terminator = Where + strlen(Name);
if (Where == Start || *(Where - 1) == ' ')
if (*Terminator == ' ' || *Terminator == '\0')
return true;
Start = Terminator;
}
return false;
}
#if !defined(QT_NO_DEBUG) && defined(GL_ARB_debug_output)
static void APIENTRY lcGLDebugCallback(GLenum Source, GLenum Type, GLuint Id, GLenum Severity, GLsizei Length, const GLchar* Message, GLvoid* UserParam)
@ -168,17 +25,12 @@ static void APIENTRY lcGLDebugCallback(GLenum Source, GLenum Type, GLuint Id, GL
#endif
void lcInitializeGLExtensions(const QGLContext* Context)
void lcInitializeGLExtensions(const QOpenGLContext* Context)
{
const GLubyte* Extensions = glGetString(GL_EXTENSIONS);
const GLubyte* Version = glGetString(GL_VERSION);
int VersionMajor = 0, VersionMinor = 0;
if (Version)
sscanf((const char*)Version, "%d.%d", &VersionMajor, &VersionMinor);
const QOpenGLFunctions* Functions = Context->functions();
#if !defined(QT_NO_DEBUG) && defined(GL_ARB_debug_output)
if (lcIsGLExtensionSupported(Extensions, "GL_KHR_debug"))
if (Context->hasExtension("GL_KHR_debug"))
{
PFNGLDEBUGMESSAGECALLBACKARBPROC DebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKARBPROC)Context->getProcAddress("glDebugMessageCallback");
@ -186,7 +38,7 @@ void lcInitializeGLExtensions(const QGLContext* Context)
#define GL_DEBUG_OUTPUT 0x92E0
#endif
if (DebugMessageCallback)
if (DebugMessageCallback)
{
DebugMessageCallback((GLDEBUGPROCARB)&lcGLDebugCallback, nullptr);
glEnable(GL_DEBUG_OUTPUT);
@ -195,181 +47,15 @@ void lcInitializeGLExtensions(const QGLContext* Context)
}
#endif
if (lcIsGLExtensionSupported(Extensions, "GL_EXT_texture_filter_anisotropic"))
if (Context->hasExtension("GL_EXT_texture_filter_anisotropic"))
{
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gMaxAnisotropy);
gSupportsAnisotropic = true;
}
// todo: check gl version and use core functions instead
if (lcIsGLExtensionSupported(Extensions, "GL_ARB_vertex_buffer_object"))
{
#ifdef LC_LOAD_GLEXTENSIONS
lcBindBufferARB = (PFNGLBINDBUFFERARBPROC)Context->getProcAddress("glBindBufferARB");
lcDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)Context->getProcAddress("glDeleteBuffersARB");
lcGenBuffersARB = (PFNGLGENBUFFERSARBPROC)Context->getProcAddress("glGenBuffersARB");
lcIsBufferARB = (PFNGLISBUFFERARBPROC)Context->getProcAddress("glIsBufferARB");
lcBufferDataARB = (PFNGLBUFFERDATAARBPROC)Context->getProcAddress("glBufferDataARB");
lcBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)Context->getProcAddress("glBufferSubDataARB");
lcGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)Context->getProcAddress("glGetBufferSubDataARB");
lcMapBufferARB = (PFNGLMAPBUFFERARBPROC)Context->getProcAddress("glMapBufferARB");
lcUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)Context->getProcAddress("glUnmapBufferARB");
lcGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)Context->getProcAddress("glGetBufferParameterivARB");
lcGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)Context->getProcAddress("glGetBufferPointervARB");
#endif
gSupportsVertexBufferObject = true;
}
// todo: check gl version
if (lcIsGLExtensionSupported(Extensions, "GL_ARB_framebuffer_object"))
{
#ifdef LC_LOAD_GLEXTENSIONS
lcIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)Context->getProcAddress("glIsRenderbuffer");
lcBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)Context->getProcAddress("glBindRenderbuffer");
lcDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)Context->getProcAddress("glDeleteRenderbuffers");
lcGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)Context->getProcAddress("glGenRenderbuffers");
lcRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)Context->getProcAddress("glRenderbufferStorage");
lcGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)Context->getProcAddress("glGetRenderbufferParameteriv");
lcIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)Context->getProcAddress("glIsFramebuffer");
lcBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)Context->getProcAddress("glBindFramebuffer");
lcDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)Context->getProcAddress("glDeleteFramebuffers");
lcGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)Context->getProcAddress("glGenFramebuffers");
lcCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)Context->getProcAddress("glCheckFramebufferStatus");
lcFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)Context->getProcAddress("glFramebufferTexture1D");
lcFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)Context->getProcAddress("glFramebufferTexture2D");
lcFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)Context->getProcAddress("glFramebufferTexture3D");
lcFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)Context->getProcAddress("glFramebufferRenderbuffer");
lcGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)Context->getProcAddress("glGetFramebufferAttachmentParameteriv");
lcGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)Context->getProcAddress("glGenerateMipmap");
lcBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)Context->getProcAddress("glBlitFramebuffer");
lcRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)Context->getProcAddress("glRenderbufferStorageMultisample");
lcFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERARBPROC)Context->getProcAddress("glFramebufferTextureLayer");
#endif
gSupportsFramebufferObjectARB = true;
}
if (lcIsGLExtensionSupported(Extensions, "GL_EXT_framebuffer_object"))
{
#ifdef LC_LOAD_GLEXTENSIONS
lcIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)Context->getProcAddress("glIsRenderbufferEXT");
lcBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)Context->getProcAddress("glBindRenderbufferEXT");
lcDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)Context->getProcAddress("glDeleteRenderbuffersEXT");
lcGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)Context->getProcAddress("glGenRenderbuffersEXT");
lcRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)Context->getProcAddress("glRenderbufferStorageEXT");
lcGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)Context->getProcAddress("glGetRenderbufferParameterivEXT");
lcIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC)Context->getProcAddress("glIsFramebufferEXT");
lcBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)Context->getProcAddress("glBindFramebufferEXT");
lcDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)Context->getProcAddress("glDeleteFramebuffersEXT");
lcGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)Context->getProcAddress("glGenFramebuffersEXT");
lcCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)Context->getProcAddress("glCheckFramebufferStatusEXT");
lcFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)Context->getProcAddress("glFramebufferTexture1DEXT");
lcFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)Context->getProcAddress("glFramebufferTexture2DEXT");
lcFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)Context->getProcAddress("glFramebufferTexture3DEXT");
lcFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)Context->getProcAddress("glFramebufferRenderbufferEXT");
lcGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)Context->getProcAddress("glGetFramebufferAttachmentParameterivEXT");
lcGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)Context->getProcAddress("glGenerateMipmapEXT");
#endif
gSupportsFramebufferObjectEXT = true;
}
if (lcIsGLExtensionSupported(Extensions, "GL_EXT_blend_func_separate"))
{
#ifdef LC_LOAD_GLEXTENSIONS
lcBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)Context->getProcAddress("glBlendFuncSeparateEXT");
#endif
gSupportsBlendFuncSeparate = true;
}
const GLubyte* GLSLVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);
int GLSLMajor = 0, GLSLMinor = 0;
if (GLSLVersion)
sscanf((const char*)GLSLVersion, "%d.%d", &GLSLMajor, &GLSLMinor);
if (VersionMajor >= 2 && (GLSLMajor > 1 || (GLSLMajor == 1 && GLSLMinor >= 10)))
{
#ifdef LC_LOAD_GLEXTENSIONS
lcAttachShader = (PFNGLATTACHSHADERPROC)Context->getProcAddress("glAttachShader");
lcBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)Context->getProcAddress("glBindAttribLocation");
lcCompileShader = (PFNGLCOMPILESHADERPROC)Context->getProcAddress("glCompileShader");
lcCreateProgram = (PFNGLCREATEPROGRAMPROC)Context->getProcAddress("glCreateProgram");
lcCreateShader = (PFNGLCREATESHADERPROC)Context->getProcAddress("glCreateShader");
lcDeleteProgram = (PFNGLDELETEPROGRAMPROC)Context->getProcAddress("glDeleteProgram");
lcDeleteShader = (PFNGLDELETESHADERPROC)Context->getProcAddress("glDeleteShader");
lcDetachShader = (PFNGLDETACHSHADERPROC)Context->getProcAddress("glDetachShader");
lcDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)Context->getProcAddress("glDisableVertexAttribArray");
lcEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)Context->getProcAddress("glEnableVertexAttribArray");
lcGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)Context->getProcAddress("glGetActiveAttrib");
lcGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)Context->getProcAddress("glGetActiveUniform");
lcGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)Context->getProcAddress("glGetAttachedShaders");
lcGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)Context->getProcAddress("glGetAttribLocation");
lcGetProgramiv = (PFNGLGETPROGRAMIVPROC)Context->getProcAddress("glGetProgramiv");
lcGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)Context->getProcAddress("glGetProgramInfoLog");
lcGetShaderiv = (PFNGLGETSHADERIVPROC)Context->getProcAddress("glGetShaderiv");
lcGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)Context->getProcAddress("glGetShaderInfoLog");
lcGetShaderSource = (PFNGLGETSHADERSOURCEPROC)Context->getProcAddress("glGetShaderSource");
lcGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)Context->getProcAddress("glGetUniformLocation");
lcGetUniformfv = (PFNGLGETUNIFORMFVPROC)Context->getProcAddress("glGetUniformfv");
lcGetUniformiv = (PFNGLGETUNIFORMIVPROC)Context->getProcAddress("glGetUniformiv");
lcGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)Context->getProcAddress("glGetVertexAttribdv");
lcGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)Context->getProcAddress("glGetVertexAttribfv");
lcGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)Context->getProcAddress("glGetVertexAttribiv");
lcGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)Context->getProcAddress("glGetVertexAttribPointerv");
lcIsProgram = (PFNGLISPROGRAMPROC)Context->getProcAddress("glIsProgram");
lcIsShader = (PFNGLISSHADERPROC)Context->getProcAddress("glIsShader");
lcLinkProgram = (PFNGLLINKPROGRAMPROC)Context->getProcAddress("glLinkProgram");
lcShaderSource = (PFNGLSHADERSOURCEPROC)Context->getProcAddress("glShaderSource");
lcUseProgram = (PFNGLUSEPROGRAMPROC)Context->getProcAddress("glUseProgram");
lcUniform1f = (PFNGLUNIFORM1FPROC)Context->getProcAddress("glUniform1f");
lcUniform2f = (PFNGLUNIFORM2FPROC)Context->getProcAddress("glUniform2f");
lcUniform3f = (PFNGLUNIFORM3FPROC)Context->getProcAddress("glUniform3f");
lcUniform4f = (PFNGLUNIFORM4FPROC)Context->getProcAddress("glUniform4f");
lcUniform1i = (PFNGLUNIFORM1IPROC)Context->getProcAddress("glUniform1i");
lcUniform2i = (PFNGLUNIFORM2IPROC)Context->getProcAddress("glUniform2i");
lcUniform3i = (PFNGLUNIFORM3IPROC)Context->getProcAddress("glUniform3i");
lcUniform4i = (PFNGLUNIFORM4IPROC)Context->getProcAddress("glUniform4i");
lcUniform1fv = (PFNGLUNIFORM1FVPROC)Context->getProcAddress("glUniform1fv");
lcUniform2fv = (PFNGLUNIFORM2FVPROC)Context->getProcAddress("glUniform2fv");
lcUniform3fv = (PFNGLUNIFORM3FVPROC)Context->getProcAddress("glUniform3fv");
lcUniform4fv = (PFNGLUNIFORM4FVPROC)Context->getProcAddress("glUniform4fv");
lcUniform1iv = (PFNGLUNIFORM1IVPROC)Context->getProcAddress("glUniform1iv");
lcUniform2iv = (PFNGLUNIFORM2IVPROC)Context->getProcAddress("glUniform2iv");
lcUniform3iv = (PFNGLUNIFORM3IVPROC)Context->getProcAddress("glUniform3iv");
lcUniform4iv = (PFNGLUNIFORM4IVPROC)Context->getProcAddress("glUniform4iv");
lcUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)Context->getProcAddress("glUniformMatrix2fv");
lcUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)Context->getProcAddress("glUniformMatrix3fv");
lcUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)Context->getProcAddress("glUniformMatrix4fv");
lcValidateProgram = (PFNGLVALIDATEPROGRAMPROC)Context->getProcAddress("glValidateProgram");
lcVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)Context->getProcAddress("glVertexAttribPointer");
#endif
gSupportsShaderObjects = true;
}
#ifndef LC_OPENGLES
if (VersionMajor > 3 || (VersionMajor == 3 && VersionMinor >= 2))
{
#ifdef LC_LOAD_GLEXTENSIONS
lcTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)Context->getProcAddress("glTexImage2DMultisample");
#endif
gSupportsTexImage2DMultisample = true;
}
if (VersionMajor >= 4)
{
#ifdef LC_LOAD_GLEXTENSIONS
lcBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)Context->getProcAddress("glBlendFuncSeparate");
#endif
gSupportsBlendFuncSeparate = true;
}
#endif
#ifdef LC_OPENGLES
gSupportsVertexBufferObject = true;
gSupportsFramebufferObjectARB = true;
gSupportsShaderObjects = true;
#endif
gSupportsVertexBufferObject = Functions->hasOpenGLFeature(QOpenGLFunctions::Buffers);
gSupportsFramebufferObject = Functions->hasOpenGLFeature(QOpenGLFunctions::Framebuffers);
gSupportsBlendFuncSeparate = Functions->hasOpenGLFeature(QOpenGLFunctions::BlendFuncSeparate);
gSupportsShaderObjects = Functions->hasOpenGLFeature(QOpenGLFunctions::Shaders);
}

View file

@ -1,236 +1,10 @@
#pragma once
void lcInitializeGLExtensions(const QGLContext* Context);
void lcInitializeGLExtensions(const QOpenGLContext* Context);
extern bool gSupportsShaderObjects;
extern bool gSupportsVertexBufferObject;
extern bool gSupportsFramebufferObjectARB;
extern bool gSupportsFramebufferObjectEXT;
extern bool gSupportsTexImage2DMultisample;
extern bool gSupportsFramebufferObject;
extern bool gSupportsBlendFuncSeparate;
extern bool gSupportsAnisotropic;
extern GLfloat gMaxAnisotropy;
#if !defined(Q_OS_MAC) && !defined(QT_OPENGL_ES)
#define LC_LOAD_GLEXTENSIONS
#endif
#ifdef LC_LOAD_GLEXTENSIONS
extern PFNGLBINDBUFFERARBPROC lcBindBufferARB;
extern PFNGLDELETEBUFFERSARBPROC lcDeleteBuffersARB;
extern PFNGLGENBUFFERSARBPROC lcGenBuffersARB;
extern PFNGLISBUFFERARBPROC lcIsBufferARB;
extern PFNGLBUFFERDATAARBPROC lcBufferDataARB;
extern PFNGLBUFFERSUBDATAARBPROC lcBufferSubDataARB;
extern PFNGLGETBUFFERSUBDATAARBPROC lcGetBufferSubDataARB;
extern PFNGLMAPBUFFERARBPROC lcMapBufferARB;
extern PFNGLUNMAPBUFFERARBPROC lcUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC lcGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC lcGetBufferPointervARB;
extern PFNGLISRENDERBUFFERPROC lcIsRenderbuffer;
extern PFNGLBINDRENDERBUFFERPROC lcBindRenderbuffer;
extern PFNGLDELETERENDERBUFFERSPROC lcDeleteRenderbuffers;
extern PFNGLGENRENDERBUFFERSPROC lcGenRenderbuffers;
extern PFNGLRENDERBUFFERSTORAGEPROC lcRenderbufferStorage;
extern PFNGLGETRENDERBUFFERPARAMETERIVPROC lcGetRenderbufferParameteriv;
extern PFNGLISFRAMEBUFFERPROC lcIsFramebuffer;
extern PFNGLBINDFRAMEBUFFERPROC lcBindFramebuffer;
extern PFNGLDELETEFRAMEBUFFERSPROC lcDeleteFramebuffers;
extern PFNGLGENFRAMEBUFFERSPROC lcGenFramebuffers;
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC lcCheckFramebufferStatus;
extern PFNGLFRAMEBUFFERTEXTURE1DPROC lcFramebufferTexture1D;
extern PFNGLFRAMEBUFFERTEXTURE2DPROC lcFramebufferTexture2D;
extern PFNGLFRAMEBUFFERTEXTURE3DPROC lcFramebufferTexture3D;
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC lcFramebufferRenderbuffer;
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC lcGetFramebufferAttachmentParameteriv;
extern PFNGLGENERATEMIPMAPPROC lcGenerateMipmap;
extern PFNGLBLITFRAMEBUFFERPROC lcBlitFramebuffer;
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC lcRenderbufferStorageMultisample;
extern PFNGLFRAMEBUFFERTEXTURELAYERPROC lcFramebufferTextureLayer;
extern PFNGLISRENDERBUFFEREXTPROC lcIsRenderbufferEXT;
extern PFNGLBINDRENDERBUFFEREXTPROC lcBindRenderbufferEXT;
extern PFNGLDELETERENDERBUFFERSEXTPROC lcDeleteRenderbuffersEXT;
extern PFNGLGENRENDERBUFFERSEXTPROC lcGenRenderbuffersEXT;
extern PFNGLRENDERBUFFERSTORAGEEXTPROC lcRenderbufferStorageEXT;
extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC lcGetRenderbufferParameterivEXT;
extern PFNGLISFRAMEBUFFEREXTPROC lcIsFramebufferEXT;
extern PFNGLBINDFRAMEBUFFEREXTPROC lcBindFramebufferEXT;
extern PFNGLDELETEFRAMEBUFFERSEXTPROC lcDeleteFramebuffersEXT;
extern PFNGLGENFRAMEBUFFERSEXTPROC lcGenFramebuffersEXT;
extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC lcCheckFramebufferStatusEXT;
extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC lcFramebufferTexture1DEXT;
extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC lcFramebufferTexture2DEXT;
extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC lcFramebufferTexture3DEXT;
extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC lcFramebufferRenderbufferEXT;
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC lcGetFramebufferAttachmentParameterivEXT;
extern PFNGLGENERATEMIPMAPEXTPROC lcGenerateMipmapEXT;
extern PFNGLATTACHSHADERPROC lcAttachShader;
extern PFNGLBINDATTRIBLOCATIONPROC lcBindAttribLocation;
extern PFNGLCOMPILESHADERPROC lcCompileShader;
extern PFNGLCREATEPROGRAMPROC lcCreateProgram;
extern PFNGLCREATESHADERPROC lcCreateShader;
extern PFNGLDELETEPROGRAMPROC lcDeleteProgram;
extern PFNGLDELETESHADERPROC lcDeleteShader;
extern PFNGLDETACHSHADERPROC lcDetachShader;
extern PFNGLDISABLEVERTEXATTRIBARRAYPROC lcDisableVertexAttribArray;
extern PFNGLENABLEVERTEXATTRIBARRAYPROC lcEnableVertexAttribArray;
extern PFNGLGETACTIVEATTRIBPROC lcGetActiveAttrib;
extern PFNGLGETACTIVEUNIFORMPROC lcGetActiveUniform;
extern PFNGLGETATTACHEDSHADERSPROC lcGetAttachedShaders;
extern PFNGLGETATTRIBLOCATIONPROC lcGetAttribLocation;
extern PFNGLGETPROGRAMIVPROC lcGetProgramiv;
extern PFNGLGETPROGRAMINFOLOGPROC lcGetProgramInfoLog;
extern PFNGLGETSHADERIVPROC lcGetShaderiv;
extern PFNGLGETSHADERINFOLOGPROC lcGetShaderInfoLog;
extern PFNGLGETSHADERSOURCEPROC lcGetShaderSource;
extern PFNGLGETUNIFORMLOCATIONPROC lcGetUniformLocation;
extern PFNGLGETUNIFORMFVPROC lcGetUniformfv;
extern PFNGLGETUNIFORMIVPROC lcGetUniformiv;
extern PFNGLGETVERTEXATTRIBDVPROC lcGetVertexAttribdv;
extern PFNGLGETVERTEXATTRIBFVPROC lcGetVertexAttribfv;
extern PFNGLGETVERTEXATTRIBIVPROC lcGetVertexAttribiv;
extern PFNGLGETVERTEXATTRIBPOINTERVPROC lcGetVertexAttribPointerv;
extern PFNGLISPROGRAMPROC lcIsProgram;
extern PFNGLISSHADERPROC lcIsShader;
extern PFNGLLINKPROGRAMPROC lcLinkProgram;
extern PFNGLSHADERSOURCEPROC lcShaderSource;
extern PFNGLUSEPROGRAMPROC lcUseProgram;
extern PFNGLUNIFORM1FPROC lcUniform1f;
extern PFNGLUNIFORM2FPROC lcUniform2f;
extern PFNGLUNIFORM3FPROC lcUniform3f;
extern PFNGLUNIFORM4FPROC lcUniform4f;
extern PFNGLUNIFORM1IPROC lcUniform1i;
extern PFNGLUNIFORM2IPROC lcUniform2i;
extern PFNGLUNIFORM3IPROC lcUniform3i;
extern PFNGLUNIFORM4IPROC lcUniform4i;
extern PFNGLUNIFORM1FVPROC lcUniform1fv;
extern PFNGLUNIFORM2FVPROC lcUniform2fv;
extern PFNGLUNIFORM3FVPROC lcUniform3fv;
extern PFNGLUNIFORM4FVPROC lcUniform4fv;
extern PFNGLUNIFORM1IVPROC lcUniform1iv;
extern PFNGLUNIFORM2IVPROC lcUniform2iv;
extern PFNGLUNIFORM3IVPROC lcUniform3iv;
extern PFNGLUNIFORM4IVPROC lcUniform4iv;
extern PFNGLUNIFORMMATRIX2FVPROC lcUniformMatrix2fv;
extern PFNGLUNIFORMMATRIX3FVPROC lcUniformMatrix3fv;
extern PFNGLUNIFORMMATRIX4FVPROC lcUniformMatrix4fv;
extern PFNGLVALIDATEPROGRAMPROC lcValidateProgram;
extern PFNGLVERTEXATTRIBPOINTERPROC lcVertexAttribPointer;
extern PFNGLTEXIMAGE2DMULTISAMPLEPROC lcTexImage2DMultisample;
extern PFNGLBLENDFUNCSEPARATEPROC lcBlendFuncSeparate;
#define glBindBuffer lcBindBufferARB
#define glDeleteBuffers lcDeleteBuffersARB
#define glGenBuffers lcGenBuffersARB
#define glIsBuffer lcIsBufferARB
#define glBufferData lcBufferDataARB
#define glBufferSubData lcBufferSubDataARB
#define glGetBufferSubData lcGetBufferSubDataARB
#define glMapBuffer lcMapBufferARB
#define glUnmapBuffer lcUnmapBufferARB
#define glGetBufferParameteriv lcGetBufferParameterivARB
#define glGetBufferPointerv lcGetBufferPointervARB
#define glIsRenderbuffer lcIsRenderbuffer
#define glBindRenderbuffer lcBindRenderbuffer
#define glDeleteRenderbuffers lcDeleteRenderbuffers
#define glGenRenderbuffers lcGenRenderbuffers
#define glRenderbufferStorage lcRenderbufferStorage
#define glGetRenderbufferParameteriv lcGetRenderbufferParameteriv
#define glIsFramebuffer lcIsFramebuffer
#define glBindFramebuffer lcBindFramebuffer
#define glDeleteFramebuffers lcDeleteFramebuffers
#define glGenFramebuffers lcGenFramebuffers
#define glCheckFramebufferStatus lcCheckFramebufferStatus
#define glFramebufferTexture1D lcFramebufferTexture1D
#define glFramebufferTexture2D lcFramebufferTexture2D
#define glFramebufferTexture3D lcFramebufferTexture3D
#define glFramebufferRenderbuffer lcFramebufferRenderbuffer
#define glGetFramebufferAttachmentParameteriv lcGetFramebufferAttachmentParameteriv
#define glGenerateMipmap lcGenerateMipmap
#define glBlitFramebuffer lcBlitFramebuffer
#define glRenderbufferStorageMultisample lcRenderbufferStorageMultisample
#define glFramebufferTextureLayer lcFramebufferTextureLayer
#define glIsRenderbufferEXT lcIsRenderbufferEXT
#define glBindRenderbufferEXT lcBindRenderbufferEXT
#define glDeleteRenderbuffersEXT lcDeleteRenderbuffersEXT
#define glGenRenderbuffersEXT lcGenRenderbuffersEXT
#define glRenderbufferStorageEXT lcRenderbufferStorageEXT
#define glGetRenderbufferParameterivEXT lcGetRenderbufferParameterivEXT
#define glIsFramebufferEXT lcIsFramebufferEXT
#define glBindFramebufferEXT lcBindFramebufferEXT
#define glDeleteFramebuffersEXT lcDeleteFramebuffersEXT
#define glGenFramebuffersEXT lcGenFramebuffersEXT
#define glCheckFramebufferStatusEXT lcCheckFramebufferStatusEXT
#define glFramebufferTexture1DEXT lcFramebufferTexture1DEXT
#define glFramebufferTexture2DEXT lcFramebufferTexture2DEXT
#define glFramebufferTexture3DEXT lcFramebufferTexture3DEXT
#define glFramebufferRenderbufferEXT lcFramebufferRenderbufferEXT
#define glGetFramebufferAttachmentParameterivEXT lcGetFramebufferAttachmentParameterivEXT
#define glGenerateMipmapEXT lcGenerateMipmapEXT
#define glAttachShader lcAttachShader
#define glBindAttribLocation lcBindAttribLocation
#define glCompileShader lcCompileShader
#define glCreateProgram lcCreateProgram
#define glCreateShader lcCreateShader
#define glDeleteProgram lcDeleteProgram
#define glDeleteShader lcDeleteShader
#define glDetachShader lcDetachShader
#define glDisableVertexAttribArray lcDisableVertexAttribArray
#define glEnableVertexAttribArray lcEnableVertexAttribArray
#define glGetActiveAttrib lcGetActiveAttrib
#define glGetActiveUniform lcGetActiveUniform
#define glGetAttachedShaders lcGetAttachedShaders
#define glGetAttribLocation lcGetAttribLocation
#define glGetProgramiv lcGetProgramiv
#define glGetProgramInfoLog lcGetProgramInfoLog
#define glGetShaderiv lcGetShaderiv
#define glGetShaderInfoLog lcGetShaderInfoLog
#define glGetShaderSource lcGetShaderSource
#define glGetUniformLocation lcGetUniformLocation
#define glGetUniformfv lcGetUniformfv
#define glGetUniformiv lcGetUniformiv
#define glGetVertexAttribdv lcGetVertexAttribdv
#define glGetVertexAttribfv lcGetVertexAttribfv
#define glGetVertexAttribiv lcGetVertexAttribiv
#define glGetVertexAttribPointerv lcGetVertexAttribPointerv
#define glIsProgram lcIsProgram
#define glIsShader lcIsShader
#define glLinkProgram lcLinkProgram
#define glShaderSource lcShaderSource
#define glUseProgram lcUseProgram
#define glUniform1f lcUniform1f
#define glUniform2f lcUniform2f
#define glUniform3f lcUniform3f
#define glUniform4f lcUniform4f
#define glUniform1i lcUniform1i
#define glUniform2i lcUniform2i
#define glUniform3i lcUniform3i
#define glUniform4i lcUniform4i
#define glUniform1fv lcUniform1fv
#define glUniform2fv lcUniform2fv
#define glUniform3fv lcUniform3fv
#define glUniform4fv lcUniform4fv
#define glUniform1iv lcUniform1iv
#define glUniform2iv lcUniform2iv
#define glUniform3iv lcUniform3iv
#define glUniform4iv lcUniform4iv
#define glUniformMatrix2fv lcUniformMatrix2fv
#define glUniformMatrix3fv lcUniformMatrix3fv
#define glUniformMatrix4fv lcUniformMatrix4fv
#define glValidateProgram lcValidateProgram
#define glVertexAttribPointer lcVertexAttribPointer
#define glTexImage2DMultisample lcTexImage2DMultisample
#define glBlendFuncSeparate lcBlendFuncSeparate
#endif

View file

@ -9,11 +9,19 @@
#include <QGLWidget>
#include <QtGui>
#include <QPrinter>
#include <QtConcurrent>
#include <map>
#include <vector>
#include <array>
#include <set>
#include <functional>
#include <memory>
#if _MSC_VER
#pragma warning(default : 4062) // enumerator 'identifier' in switch of enum 'enumeration' is not handled
#pragma warning(default : 4388) // 'token' : signed/unsigned mismatch
#pragma warning(default : 4389) // 'equality-operator' : signed/unsigned mismatch
#endif
#ifndef Q_FALLTHROUGH
#define Q_FALLTHROUGH();
@ -25,13 +33,9 @@
#endif
#define LC_ARRAY_COUNT(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
#define LC_ARRAY_SIZE_CHECK(a,s) static_assert(LC_ARRAY_COUNT(a) == static_cast<int>(s), QT_STRINGIFY(a) " size mismatch.")
#if !defined(EGL_VERSION_1_0) && !defined(GL_ES_VERSION_2_0) && !defined(GL_ES_VERSION_3_0) && !defined(QT_OPENGL_ES)
#undef GL_LINES_ADJACENCY_EXT
#undef GL_LINE_STRIP_ADJACENCY_EXT
#undef GL_TRIANGLES_ADJACENCY_EXT
#undef GL_TRIANGLE_STRIP_ADJACENCY_EXT
#include "lc_glext.h"
#else
#define LC_OPENGLES 1
#endif
@ -40,18 +44,20 @@
#define LC_MAXPATH 1024
#define LC_MAXNAME 1000
typedef quint32 lcStep;
#define LC_STEP_MAX 0xffffffff
#ifdef Q_OS_WIN
char* strcasestr(const char *s, const char *find);
#else
char* strupr(char* string);
char* strlwr(char* string);
#endif
// Version number.
#define LC_VERSION_MAJOR 19
#define LC_VERSION_MINOR 07
#define LC_VERSION_PATCH 1
#define LC_VERSION_TEXT "19.07.1"
#define LC_VERSION_MAJOR 21
#define LC_VERSION_MINOR 01
#define LC_VERSION_PATCH 0
#define LC_VERSION_TEXT "21.01"
// Forward declarations.
class Project;
@ -64,6 +70,14 @@ class lcGroup;
class PieceInfo;
typedef std::map<const PieceInfo*, std::map<int, int>> lcPartsList;
struct lcModelPartsEntry;
struct lcMinifig;
enum class lcViewpoint;
enum class lcShadingMode;
enum class lcStudStyle;
class lcInstructions;
struct lcInstructionsPageSetup;
struct lcObjectRayTest;
struct lcObjectBoxTest;
class lcVector2;
class lcVector3;
@ -71,12 +85,19 @@ class lcVector4;
class lcMatrix33;
class lcMatrix44;
class lcFindReplaceWidget;
struct lcFindReplaceParams;
class lcCollapsibleWidget;
class lcViewWidget;
class lcView;
class lcContext;
class lcMesh;
struct lcMeshSection;
struct lcRenderMesh;
struct lcObjectSection;
class lcTexture;
class lcScene;
class lcViewSphere;
enum class lcRenderMeshState : int;
class lcFile;

View file

@ -1,96 +0,0 @@
#pragma once
#include "lc_context.h"
enum class lcCursor
{
Default,
Brick,
Light,
Spotlight,
Camera,
Select,
SelectAdd,
SelectRemove,
Move,
Rotate,
RotateX,
RotateY,
Delete,
Paint,
ColorPicker,
Zoom,
ZoomRegion,
Pan,
Roll,
RotateView,
Count
};
struct lcInputState
{
int x;
int y;
Qt::KeyboardModifiers Modifiers;
};
class lcGLWidget
{
public:
lcGLWidget()
{
mCursor = lcCursor::Default;
mWidget = nullptr;
mInputState.x = 0;
mInputState.y = 0;
mInputState.Modifiers = Qt::NoModifier;
mWidth = 1;
mHeight = 1;
mContext = new lcContext();
mDeleteContext = true;
}
virtual ~lcGLWidget()
{
if (mDeleteContext)
delete mContext;
}
void SetContext(lcContext* Context)
{
if (mDeleteContext)
delete mContext;
mContext = Context;
mDeleteContext = false;
}
void MakeCurrent();
void Redraw();
void SetCursor(lcCursor Cursor);
virtual void OnDraw() { }
virtual void OnInitialUpdate() { }
virtual void OnUpdateCursor() { }
virtual void OnLeftButtonDown() { }
virtual void OnLeftButtonUp() { }
virtual void OnLeftButtonDoubleClick() { }
virtual void OnMiddleButtonDown() { }
virtual void OnMiddleButtonUp() { }
virtual void OnRightButtonDown() { }
virtual void OnRightButtonUp() { }
virtual void OnBackButtonDown() { }
virtual void OnBackButtonUp() { }
virtual void OnForwardButtonDown() { }
virtual void OnForwardButtonUp() { }
virtual void OnMouseMove() { }
virtual void OnMouseWheel(float Direction) { Q_UNUSED(Direction); }
lcInputState mInputState;
int mWidth;
int mHeight;
lcCursor mCursor;
void* mWidget;
lcContext* mContext;
bool mDeleteContext;
};

253
common/lc_instructions.cpp Normal file
View file

@ -0,0 +1,253 @@
#include "lc_global.h"
#include "lc_instructions.h"
#include "project.h"
#include "lc_model.h"
#include "piece.h"
#include "pieceinf.h"
const float lcInstructions::mDisplayDPI = 72.0f;
lcInstructions::lcInstructions(Project* Project)
: mProject(Project)
{
mPageSetup.Width = 8.5f * mDisplayDPI;
mPageSetup.Height = 11.0f * mDisplayDPI;
mPageSetup.MarginLeft = 0.5 * mDisplayDPI;
mPageSetup.MarginRight = 0.5 * mDisplayDPI;
mPageSetup.MarginTop = 0.5 * mDisplayDPI;
mPageSetup.MarginBottom = 0.5 * mDisplayDPI;
mPageSettings.Rows = 1;
mPageSettings.Columns = 1;
mPageSettings.Direction = lcInstructionsDirection::Horizontal;
mStepProperties[static_cast<int>(lcInstructionsPropertyType::ShowStepNumber)].Value = true;
mStepProperties[static_cast<int>(lcInstructionsPropertyType::ShowStepPLI)].Value = true;
mStepProperties[static_cast<int>(lcInstructionsPropertyType::StepNumberFont)].Value = QFont("Arial", 72).toString();
mStepProperties[static_cast<int>(lcInstructionsPropertyType::StepNumberColor)].Value = LC_RGBA(0, 0, 0, 255);
mStepProperties[static_cast<int>(lcInstructionsPropertyType::StepBackgroundColor)].Value = LC_RGBA(255, 255, 255, 0);
mStepProperties[static_cast<int>(lcInstructionsPropertyType::PLIBackgroundColor)].Value = LC_RGBA(255, 255, 255, 255);
mStepProperties[static_cast<int>(lcInstructionsPropertyType::PLIFont)].Value = QFont("Arial", 16, QFont::Bold).toString();
mStepProperties[static_cast<int>(lcInstructionsPropertyType::PLITextColor)].Value = LC_RGBA(0, 0, 0, 255);
mStepProperties[static_cast<int>(lcInstructionsPropertyType::PLIBorderColor)].Value = LC_RGBA(0, 0, 0, 255);
// mStepProperties[static_cast<int>(lcInstructionsPropertyType::PLIBorderWidth)].Value = 2.0f;
// mStepProperties[static_cast<int>(lcInstructionsPropertyType::PLIBorderRound)].Value = true;
static_assert(static_cast<int>(lcInstructionsPropertyType::Count) == 9, "Missing default property");
CreatePages();
}
QString lcInstructions::GetPropertyLabel(lcInstructionsPropertyType Type)
{
switch (Type)
{
case lcInstructionsPropertyType::ShowStepNumber:
return tr("Show Step Number");
case lcInstructionsPropertyType::ShowStepPLI:
return tr("Show Parts List");
case lcInstructionsPropertyType::StepNumberFont:
return tr("Font:");
case lcInstructionsPropertyType::StepNumberColor:
return tr("Text Color:");
case lcInstructionsPropertyType::StepBackgroundColor:
return tr("Background Color:");
case lcInstructionsPropertyType::PLIBackgroundColor:
return tr("Background Color:");
case lcInstructionsPropertyType::PLIFont:
return tr("Font:");
case lcInstructionsPropertyType::PLITextColor:
return tr("Text Color:");
case lcInstructionsPropertyType::PLIBorderColor:
return tr("Border Color:");
case lcInstructionsPropertyType::Count:
break;
}
return QString();
}
void lcInstructions::SetDefaultPageSettings(const lcInstructionsPageSettings& PageSettings)
{
mPageSettings = PageSettings;
CreatePages();
}
bool lcInstructions::GetBoolProperty(lcInstructionsPropertyType Type, lcModel* Model, lcStep Step) const
{
QVariant Value = GetProperty(Type, Model, Step);
return Value.toBool();
}
QColor lcInstructions::GetColorProperty(lcInstructionsPropertyType Type, lcModel* Model, lcStep Step) const
{
QVariant Value = GetProperty(Type, Model, Step);
return lcRGBAFromQColor(Value.toUInt());
}
QFont lcInstructions::GetFontProperty(lcInstructionsPropertyType Type, lcModel* Model, lcStep Step) const
{
QVariant Value = GetProperty(Type, Model, Step);
QFont Font;
Font.fromString(Value.toString());
return Font;
}
QVariant lcInstructions::GetProperty(lcInstructionsPropertyType Type, lcModel* Model, lcStep Step) const
{
QVariant Value = mStepProperties[static_cast<int>(Type)].Value;
std::map<lcModel*, lcInstructionsModel>::const_iterator ModelIt = mModels.find(Model);
if (ModelIt == mModels.end())
return Value;
const lcInstructionsModel& InstructionModel = ModelIt->second;
for (lcStep StepIndex = 0; StepIndex <= Step; StepIndex++)
{
const lcInstructionsProperties& Properties = InstructionModel.StepProperties[StepIndex];
const lcInstructionsProperty& Property = Properties[static_cast<int>(Type)];
if (Property.Mode == lcInstructionsPropertyMode::NotSet || (Property.Mode == lcInstructionsPropertyMode::StepOnly && StepIndex != Step))
continue;
Value = Property.Value;
}
return Value;
}
void lcInstructions::SetDefaultBool(lcInstructionsPropertyType Type, bool Enabled)
{
SetDefaultProperty(Type, Enabled);
}
void lcInstructions::SetDefaultColor(lcInstructionsPropertyType Type, const QColor& Color)
{
SetDefaultProperty(Type, lcRGBAFromQColor(Color));
}
void lcInstructions::SetDefaultFont(lcInstructionsPropertyType Type, const QFont& Font)
{
SetDefaultProperty(Type, Font.toString());
}
void lcInstructions::SetDefaultProperty(lcInstructionsPropertyType Type, const QVariant& Value)
{
lcInstructionsProperty& Property = mStepProperties[static_cast<int>(Type)];
if (Property.Value == Value)
return;
Property.Value = Value;
emit StepSettingsChanged(nullptr, 0);
}
void lcInstructions::CreatePages()
{
mPages.clear();
if (mProject)
{
std::vector<const lcModel*> AddedModels;
lcModel* Model = mProject->GetMainModel();
if (Model)
AddDefaultPages(Model, AddedModels);
}
}
void lcInstructions::AddDefaultPages(lcModel* Model, std::vector<const lcModel*>& AddedModels)
{
if (std::find(AddedModels.begin(), AddedModels.end(), Model) != AddedModels.end())
return;
AddedModels.push_back(Model);
const lcStep LastStep = Model->GetLastStep();
lcInstructionsPage Page;
int Row = 0, Column = 0;
lcInstructionsModel InstructionModel;
InstructionModel.StepProperties.resize(LastStep + 1);
mModels.emplace(Model, std::move(InstructionModel));
for (lcStep Step = 1; Step <= LastStep; Step++)
{
std::set<lcModel*> StepSubModels;
for (lcPiece* Piece : Model->GetPieces())
{
if (!Piece->IsHidden() && Piece->GetStepShow() == Step && Piece->mPieceInfo->IsModel())
{
lcModel* SubModel = Piece->mPieceInfo->GetModel();
if (std::find(AddedModels.begin(), AddedModels.end(), SubModel) != AddedModels.end())
StepSubModels.insert(SubModel);
}
}
if (!StepSubModels.empty())
{
if (!Page.Steps.empty())
{
mPages.emplace_back(std::move(Page));
Row = 0;
Column = 0;
}
for (lcModel* SubModel : StepSubModels)
AddDefaultPages(SubModel, AddedModels);
}
lcInstructionsStep InstructionsStep;
InstructionsStep.Model = Model;
InstructionsStep.Step = Step;
const double Width = 1.0 / (double)mPageSettings.Columns;
const double Height = 1.0 / (double)mPageSettings.Rows;
InstructionsStep.Rect = QRectF(Column * Width, Row * Height, Width, Height);
Page.Steps.push_back(std::move(InstructionsStep));
if (mPageSettings.Direction == lcInstructionsDirection::Horizontal)
{
Column++;
if (Column == mPageSettings.Columns)
{
Row++;
Column = 0;
}
if (Row == mPageSettings.Rows)
{
mPages.emplace_back(std::move(Page));
Row = 0;
Column = 0;
}
}
else
{
Row++;
if (Row == mPageSettings.Rows)
{
Row = 0;
Column++;
}
if (Column == mPageSettings.Columns)
{
mPages.emplace_back(std::move(Page));
Row = 0;
Column = 0;
}
}
}
}

122
common/lc_instructions.h Normal file
View file

@ -0,0 +1,122 @@
#pragma once
#include "lc_math.h"
struct lcInstructionsPageSetup
{
float Width;
float Height;
float MarginLeft;
float MarginRight;
float MarginTop;
float MarginBottom;
};
enum class lcInstructionsDirection
{
Horizontal,
Vertical
};
struct lcInstructionsPageSettings
{
int Rows;
int Columns;
lcInstructionsDirection Direction;
};
enum class lcInstructionsPropertyMode
{
NotSet,
Default,
Model,
StepForward,
StepOnly
};
enum class lcInstructionsPropertyType
{
ShowStepNumber,
ShowStepPLI,
StepNumberFont,
StepNumberColor,
StepBackgroundColor,
PLIBackgroundColor,
PLIFont,
PLITextColor,
PLIBorderColor,
// PLIBorderWidth,
// PLIBorderRound,
// pli: spacing and margins, text alignment
Count
};
struct lcInstructionsProperty
{
lcInstructionsPropertyMode Mode = lcInstructionsPropertyMode::NotSet;
QVariant Value;
};
using lcInstructionsProperties = std::array<lcInstructionsProperty, static_cast<int>(lcInstructionsPropertyType::Count)>;
struct lcInstructionsStep
{
QRectF Rect;
lcModel* Model;
lcStep Step;
lcInstructionsProperties Properties;
};
struct lcInstructionsPage
{
// lcInstructionsPageSettings Settings;
std::vector<lcInstructionsStep> Steps;
};
struct lcInstructionsModel
{
std::vector<lcInstructionsProperties> StepProperties;
};
class lcInstructions : public QObject
{
Q_OBJECT
public:
lcInstructions(Project* Project = nullptr);
static QString GetPropertyLabel(lcInstructionsPropertyType Type);
void SetDefaultPageSettings(const lcInstructionsPageSettings& PageSettings);
bool GetBoolProperty(lcInstructionsPropertyType Type, lcModel* Model, lcStep Step) const;
QColor GetColorProperty(lcInstructionsPropertyType Type, lcModel* Model, lcStep Step) const;
QFont GetFontProperty(lcInstructionsPropertyType Type, lcModel* Model, lcStep Step) const;
void SetDefaultBool(lcInstructionsPropertyType Type, bool Enabled);
void SetDefaultColor(lcInstructionsPropertyType Type, const QColor& Color);
void SetDefaultFont(lcInstructionsPropertyType Type, const QFont& Font);
//protected:
std::vector<lcInstructionsPage> mPages;
lcInstructionsPageSettings mPageSettings;
lcInstructionsPageSetup mPageSetup;
lcInstructionsProperties mStepProperties;
std::map<lcModel*, lcInstructionsModel> mModels;
signals:
void StepSettingsChanged(lcModel* Model, lcStep Step);
protected:
void CreatePages();
void AddDefaultPages(lcModel* Model, std::vector<const lcModel*>& AddedModels);
QVariant GetProperty(lcInstructionsPropertyType Type, lcModel* Model, lcStep Step) const;
void SetDefaultProperty(lcInstructionsPropertyType Type, const QVariant& Value);
Project* mProject = nullptr;
static const float mDisplayDPI;
};

View file

@ -0,0 +1,632 @@
#include "lc_global.h"
#include "lc_instructionsdialog.h"
#include "lc_pagesetupdialog.h"
#include "project.h"
#include "lc_model.h"
#include "lc_view.h"
#include "lc_collapsiblewidget.h"
lcInstructionsStepImageItem::lcInstructionsStepImageItem(QGraphicsItem* Parent, lcInstructions* Instructions, lcModel* Model, lcStep Step)
: QGraphicsPixmapItem(Parent), mInstructions(Instructions), mModel(Model), mStep(Step)
{
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);
}
void lcInstructionsStepImageItem::Update()
{
lcView View(lcViewType::View, mModel);
View.SetOffscreenContext();
View.MakeCurrent();
View.SetBackgroundColorOverride(lcRGBAFromQColor(mInstructions->GetColorProperty(lcInstructionsPropertyType::StepBackgroundColor, mModel, mStep)));
View.SetSize(mWidth, mHeight);
std::vector<QImage> Images = View.GetStepImages(mStep, mStep);
if (!Images.empty())
setPixmap(QPixmap::fromImage(Images.front()));
}
lcInstructionsStepNumberItem::lcInstructionsStepNumberItem(QGraphicsItem* Parent, lcInstructions* Instructions, lcModel* Model, lcStep Step)
: QGraphicsSimpleTextItem(Parent), mInstructions(Instructions), mModel(Model), mStep(Step)
{
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);
}
void lcInstructionsStepNumberItem::Update()
{
bool Visible = mInstructions->GetBoolProperty(lcInstructionsPropertyType::ShowStepNumber, mModel, mStep);
setVisible(Visible);
QFont StepNumberFont = mInstructions->GetFontProperty(lcInstructionsPropertyType::StepNumberFont, mModel, mStep);
setFont(StepNumberFont);
setBrush(QBrush(mInstructions->GetColorProperty(lcInstructionsPropertyType::StepNumberColor, mModel, mStep)));
setText(QString::number(mStep));
}
lcInstructionsPartsListItem::lcInstructionsPartsListItem(QGraphicsItem* Parent, lcInstructions* Instructions, lcModel* Model, lcStep Step)
: QGraphicsPixmapItem(Parent), mInstructions(Instructions), mModel(Model), mStep(Step)
{
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);
}
void lcInstructionsPartsListItem::Update()
{
bool Visible = mInstructions->GetBoolProperty(lcInstructionsPropertyType::ShowStepPLI, mModel, mStep);
setVisible(Visible);
if (!Visible)
return;
QColor BackgroundColor = mInstructions->GetColorProperty(lcInstructionsPropertyType::PLIBackgroundColor, mModel, mStep);
QFont Font = mInstructions->GetFontProperty(lcInstructionsPropertyType::PLIFont, mModel, mStep);
QColor TextColor = mInstructions->GetColorProperty(lcInstructionsPropertyType::PLITextColor, mModel, mStep);
QImage PartsImage = mModel->GetPartsListImage(300, mStep, lcRGBAFromQColor(BackgroundColor), Font, TextColor);
setPixmap(QPixmap::fromImage(PartsImage));
}
lcInstructionsPageWidget::lcInstructionsPageWidget(QWidget* Parent, lcInstructions* Instructions, lcInstructionsPropertiesWidget* PropertiesWidget)
: QGraphicsView(Parent), mInstructions(Instructions), mPropertiesWidget(PropertiesWidget)
{
QGraphicsScene* Scene = new QGraphicsScene();
setScene(Scene);
connect(mInstructions, &lcInstructions::StepSettingsChanged, this, &lcInstructionsPageWidget::StepSettingsChanged);
connect(Scene, &QGraphicsScene::selectionChanged, this, &lcInstructionsPageWidget::SelectionChanged);
}
void lcInstructionsPageWidget::StepSettingsChanged(lcModel* Model, lcStep Step)
{
QGraphicsScene* Scene = scene();
QList<QGraphicsItem*> Items = Scene->items();
for (QGraphicsItem* Item : Items)
{
lcInstructionsStepImageItem* ImageItem = dynamic_cast<lcInstructionsStepImageItem*>(Item);
if (ImageItem)
{
if (!Model || (ImageItem->GetModel() == Model && ImageItem->GetStep() == Step))
ImageItem->Update();
continue;
}
lcInstructionsStepNumberItem* NumberItem = dynamic_cast<lcInstructionsStepNumberItem*>(Item);
if (NumberItem)
{
if (!Model || (NumberItem->GetModel() == Model && NumberItem->GetStep() == Step))
NumberItem->Update();
continue;
}
lcInstructionsPartsListItem* PartsItem = dynamic_cast<lcInstructionsPartsListItem*>(Item);
if (PartsItem)
{
if (!Model || (PartsItem->GetModel() == Model && PartsItem->GetStep() == Step))
PartsItem->Update();
continue;
}
}
}
void lcInstructionsPageWidget::SelectionChanged()
{
QGraphicsScene* Scene = qobject_cast<QGraphicsScene*>(sender());
QGraphicsItem* Focus = nullptr;
if (Scene)
{
QList<QGraphicsItem*> SelectedItems = Scene->selectedItems();
if (!SelectedItems.isEmpty())
Focus = SelectedItems.first();
}
mPropertiesWidget->SelectionChanged(Focus);
}
void lcInstructionsPageWidget::SetCurrentPage(const lcInstructionsPage* Page)
{
QGraphicsScene* Scene = scene();
Scene->clear();
if (!Page)
return;
const lcInstructionsPageSetup& PageSetup = mInstructions->mPageSetup;
// Scene->setSceneRect(0, 0, mInstructions->mPageSetup.Width, mInstructions->mPageSetup.Height);
QGraphicsRectItem* PageItem = Scene->addRect(QRectF(0.0f, 0.0f, PageSetup.Width, PageSetup.Height), QPen(Qt::black), QBrush(Qt::white));
PageItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
QRectF MarginsRect(PageSetup.MarginLeft, PageSetup.MarginTop, PageSetup.Width - PageSetup.MarginLeft - PageSetup.MarginRight, PageSetup.Height - PageSetup.MarginTop - PageSetup.MarginBottom);
for (const lcInstructionsStep& Step : Page->Steps)
{
lcInstructionsStepImageItem* StepImageItem = new lcInstructionsStepImageItem(PageItem, mInstructions, Step.Model, Step.Step);
StepImageItem->setPos(MarginsRect.left() + MarginsRect.width() * Step.Rect.x(), MarginsRect.top() + MarginsRect.height() * Step.Rect.y());
StepImageItem->SetImageSize(MarginsRect.width() * Step.Rect.width(), MarginsRect.height() * Step.Rect.height());
StepImageItem->Update();
lcInstructionsStepNumberItem* StepNumberItem = new lcInstructionsStepNumberItem(StepImageItem, mInstructions, Step.Model, Step.Step);
StepNumberItem->Update();
lcInstructionsPartsListItem* PartsImageItem = new lcInstructionsPartsListItem(StepImageItem, mInstructions, Step.Model, Step.Step);
PartsImageItem->setPos(StepNumberItem->boundingRect().topRight());
PartsImageItem->Update();
}
}
lcInstructionsPageListWidget::lcInstructionsPageListWidget(QWidget* Parent, lcInstructions* Instructions)
: QDockWidget(Parent), mInstructions(Instructions)
{
QWidget* CentralWidget = new QWidget(this);
setWidget(CentralWidget);
setWindowTitle(tr("Pages"));
QVBoxLayout* Layout = new QVBoxLayout(CentralWidget);
Layout->setContentsMargins(0, 0, 0, 0);
QHBoxLayout* ButtonsLayout = new QHBoxLayout();
ButtonsLayout->setContentsMargins(0, 0, 0, 0);
Layout->addLayout(ButtonsLayout);
QToolButton* PageSetupButton = new QToolButton();
PageSetupButton->setText("Page Setup");
ButtonsLayout->addWidget(PageSetupButton);
connect(PageSetupButton, SIGNAL(clicked()), this, SLOT(ShowPageSetupDialog()));
ButtonsLayout->addStretch(1);
/*
lcCollapsibleWidget* SetupWidget = new lcCollapsibleWidget(tr("Page Setup"), CentralWidget);
Layout->addWidget(SetupWidget);
// QVBoxLayout* SetupLayout = new QVBoxLayout();
// SetupWidget->SetChildLayout(SetupLayout);
QGridLayout* SetupLayout = new QGridLayout();
SetupWidget->SetChildLayout(SetupLayout);
// lcCollapsibleWidget* SizeWidget = new lcCollapsibleWidget(tr("Size"));
QGroupBox* SizeWidget = new QGroupBox(tr("Size"));
SetupLayout->addWidget(SizeWidget);
QGridLayout* SizeLayout = new QGridLayout();
// SizeWidget->SetChildLayout(SizeLayout);
SizeWidget->setLayout(SizeLayout);
mWidthEdit = new lcSmallLineEdit();
SizeLayout->addWidget(new QLabel(tr("Width:")), 1, 0);
SizeLayout->addWidget(mWidthEdit, 1, 1);
mHeightEdit = new lcSmallLineEdit();
SizeLayout->addWidget(new QLabel(tr("Height:")), 1, 2);
SizeLayout->addWidget(mHeightEdit, 1, 3);
mUnitsComboBox = new QComboBox();
mUnitsComboBox->addItems(QStringList() << tr("Pixels") << tr("Centimeters") << tr("Inches"));
SizeLayout->addWidget(new QLabel(tr("Units:")), 4, 0);
SizeLayout->addWidget(mUnitsComboBox, 4, 1, 1, -1);
mSizeComboBox = new QComboBox();
SizeLayout->addWidget(new QLabel(tr("Preset:")), 5, 0);
SizeLayout->addWidget(mSizeComboBox, 5, 1, 1, -1);
// lcCollapsibleWidget* OrientationWidget = new lcCollapsibleWidget(tr("Orientation"));
// SetupLayout->addWidget(OrientationWidget);
//
// QVBoxLayout* OrientationLayout = new QVBoxLayout();
// OrientationWidget->SetChildLayout(OrientationLayout);
//
// mPortraitButton = new QRadioButton(tr("Portrait"));
// OrientationLayout->addWidget(mPortraitButton);
// mLandscapeButton = new QRadioButton(tr("Landscape"));
// OrientationLayout->addWidget(mLandscapeButton);
QGroupBox* MarginsWidget = new QGroupBox(tr("Margins"));
// lcCollapsibleWidget* MarginsWidget = new lcCollapsibleWidget(tr("Margins"));
SetupLayout->addWidget(MarginsWidget);
QGridLayout* MarginsLayout = new QGridLayout();
// MarginsWidget->SetChildLayout(MarginsLayout);
MarginsWidget->setLayout(MarginsLayout);
mLeftMarginEdit = new lcSmallLineEdit();
MarginsLayout->addWidget(new QLabel(tr("Left:")), 2, 0);
MarginsLayout->addWidget(mLeftMarginEdit, 2, 1);
mRightMarginEdit = new lcSmallLineEdit();
MarginsLayout->addWidget(new QLabel(tr("Right:")), 2, 2);
MarginsLayout->addWidget(mRightMarginEdit, 2, 3);
mTopMarginEdit = new lcSmallLineEdit();
MarginsLayout->addWidget(new QLabel(tr("Top:")), 3, 0);
MarginsLayout->addWidget(mTopMarginEdit, 3, 1);
mBottomMarginEdit = new lcSmallLineEdit();
MarginsLayout->addWidget(new QLabel(tr("Bottom:")), 3, 2);
MarginsLayout->addWidget(mBottomMarginEdit, 3, 3);
// lcCollapsibleWidget* UnitsWidget = new lcCollapsibleWidget(tr("Units"));
// SetupLayout->addWidget(UnitsWidget);
//
// QVBoxLayout* UnitsLayout = new QVBoxLayout();
// UnitsWidget->SetChildLayout(UnitsLayout);
// SetupWidget->Collapse();
*/
mThumbnailsWidget = new QListWidget(CentralWidget);
Layout->addWidget(mThumbnailsWidget);
}
void lcInstructionsPageListWidget::ShowPageSetupDialog()
{
lcPageSetupDialog Dialog(this, &mInstructions->mPageSetup);
if (Dialog.exec() != QDialog::Accepted)
return;
}
lcInstructionsPropertiesWidget::lcInstructionsPropertiesWidget(QWidget* Parent, lcInstructions* Instructions)
: QDockWidget(Parent), mInstructions(Instructions)
{
QWidget* CentralWidget = new QWidget(this);
setWidget(CentralWidget);
setWindowTitle(tr("Properties"));
QGridLayout* Layout = new QGridLayout(CentralWidget);
Layout->setContentsMargins(0, 0, 0, 0);
QComboBox* ScopeComboBox = new QComboBox(CentralWidget);
ScopeComboBox->addItems(QStringList() << tr("Default") << tr("Current Model") << tr("Current Step Only") << tr("Current Step Forward"));
Layout->addWidget(new QLabel(tr("Scope:")), 0, 0);
Layout->addWidget(ScopeComboBox, 0, 1);
QComboBox* PresetComboBox = new QComboBox(CentralWidget);
Layout->addWidget(new QLabel(tr("Preset:")), 1, 0);
Layout->addWidget(PresetComboBox, 1, 1);
Layout->setRowStretch(3, 1);
}
void lcInstructionsPropertiesWidget::AddBoolProperty(lcInstructionsPropertyType Type)
{
const QString Label = mInstructions->GetPropertyLabel(Type);
const int Row = mPropertiesLayout->rowCount();
QCheckBox* CheckBox = new QCheckBox(Label);
mPropertiesLayout->addWidget(CheckBox, Row, 0, 1, -1);
bool Enabled = mInstructions->GetBoolProperty(Type, mModel, mStep);
CheckBox->setChecked(Enabled);
connect(CheckBox, &QToolButton::toggled, [this, Type](bool Checked)
{
mInstructions->SetDefaultBool(Type, Checked);
} );
}
void lcInstructionsPropertiesWidget::AddColorProperty(lcInstructionsPropertyType Type)
{
const QString Label = mInstructions->GetPropertyLabel(Type);
const int Row = mPropertiesLayout->rowCount();
mPropertiesLayout->addWidget(new QLabel(Label), Row, 0);
QToolButton* ColorButton = new QToolButton();
mPropertiesLayout->addWidget(ColorButton, Row, 1);
auto UpdateButton = [this, Type, ColorButton]()
{
QPixmap Pixmap(12, 12);
QColor Color = mInstructions->GetColorProperty(Type, mModel, mStep);
Pixmap.fill(Color);
ColorButton->setIcon(Pixmap);
};
UpdateButton();
connect(ColorButton, &QToolButton::clicked, [this, Type, UpdateButton]()
{
QString Title;
switch (Type)
{
case lcInstructionsPropertyType::StepNumberColor:
Title = tr("Select Step Number Color");
break;
case lcInstructionsPropertyType::StepBackgroundColor:
Title = tr("Select Step Background Color");
break;
case lcInstructionsPropertyType::PLIBackgroundColor:
Title = tr("Select Parts List Background Color");
break;
case lcInstructionsPropertyType::PLIBorderColor:
Title = tr("Select Parts List Border Color");
break;
case lcInstructionsPropertyType::PLITextColor:
Title = tr("Select Parts List Text Color");
break;
case lcInstructionsPropertyType::ShowStepNumber:
case lcInstructionsPropertyType::ShowStepPLI:
case lcInstructionsPropertyType::StepNumberFont:
case lcInstructionsPropertyType::PLIFont:
// case lcInstructionsPropertyType::StepPLIBorderWidth:
// case lcInstructionsPropertyType::StepPLIBorderRound:
case lcInstructionsPropertyType::Count:
break;
}
QColor Color = mInstructions->GetColorProperty(Type, mModel, mStep);
Color = QColorDialog::getColor(Color, this, Title);
if (Color.isValid())
{
mInstructions->SetDefaultColor(Type, Color);
UpdateButton();
}
});
}
void lcInstructionsPropertiesWidget::AddFontProperty(lcInstructionsPropertyType Type)
{
const QString Label = mInstructions->GetPropertyLabel(Type);
const int Row = mPropertiesLayout->rowCount();
mPropertiesLayout->addWidget(new QLabel(Label), Row, 0);
QToolButton* FontButton = new QToolButton();
mPropertiesLayout->addWidget(FontButton, Row, 1);
auto UpdateButton = [this, Type, FontButton]()
{
QFont Font = mInstructions->GetFontProperty(Type, mModel, mStep);
QString FontName = QString("%1 %2").arg(Font.family(), QString::number(Font.pointSize()));
FontButton->setText(FontName);
};
UpdateButton();
connect(FontButton, &QToolButton::clicked, [this, Type, UpdateButton]()
{
QString Title;
switch (Type)
{
case lcInstructionsPropertyType::StepNumberFont:
Title = tr("Select Step Number Font");
break;
case lcInstructionsPropertyType::PLIFont:
Title = tr("Select Parts List Font");
break;
case lcInstructionsPropertyType::ShowStepNumber:
case lcInstructionsPropertyType::ShowStepPLI:
case lcInstructionsPropertyType::StepNumberColor:
case lcInstructionsPropertyType::StepBackgroundColor:
case lcInstructionsPropertyType::PLIBackgroundColor:
case lcInstructionsPropertyType::PLITextColor:
case lcInstructionsPropertyType::PLIBorderColor:
case lcInstructionsPropertyType::Count:
break;
}
bool Ok = false;
QFont Font = mInstructions->GetFontProperty(Type, mModel, mStep);
Font = QFontDialog::getFont(&Ok, Font, this, tr("Select Step Number Font"));
if (Ok)
{
UpdateButton();
mInstructions->SetDefaultFont(Type, Font);
}
});
}
void lcInstructionsPropertiesWidget::SelectionChanged(QGraphicsItem* FocusItem)
{
if (mFocusItem == FocusItem)
return;
delete mWidget;
mWidget = nullptr;
mFocusItem = FocusItem;
mModel = nullptr;
mStep = 1;
if (!FocusItem)
return;
auto CreatePropertyWidget = [this](const QString& Title)
{
mWidget = new lcCollapsibleWidget(Title); // todo: disable collapse
QGridLayout* WidgetLayout = qobject_cast<QGridLayout*>(widget()->layout());
WidgetLayout->addWidget(mWidget, 2, 0, 1, -1);
mPropertiesLayout = new QGridLayout();
mWidget->SetChildLayout(mPropertiesLayout);
};
lcInstructionsStepImageItem* ImageItem = dynamic_cast<lcInstructionsStepImageItem*>(FocusItem);
if (ImageItem)
{
CreatePropertyWidget(tr("Step Properties"));
mModel = ImageItem->GetModel();
mStep = ImageItem->GetStep();
AddBoolProperty(lcInstructionsPropertyType::ShowStepNumber);
AddBoolProperty(lcInstructionsPropertyType::ShowStepPLI);
AddColorProperty(lcInstructionsPropertyType::StepBackgroundColor);
return;
}
lcInstructionsStepNumberItem* NumberItem = dynamic_cast<lcInstructionsStepNumberItem*>(FocusItem);
if (NumberItem)
{
CreatePropertyWidget(tr("Step Number Properties"));
mModel = NumberItem->GetModel();
mStep = NumberItem->GetStep();
AddFontProperty(lcInstructionsPropertyType::StepNumberFont);
AddColorProperty(lcInstructionsPropertyType::StepNumberColor);
return;
}
lcInstructionsPartsListItem* PartsItem = dynamic_cast<lcInstructionsPartsListItem*>(FocusItem);
if (PartsItem)
{
CreatePropertyWidget(tr("Parts List Properties"));
mModel = PartsItem->GetModel();
mStep = PartsItem->GetStep();
AddColorProperty(lcInstructionsPropertyType::PLIBackgroundColor);
AddFontProperty(lcInstructionsPropertyType::PLIFont);
AddColorProperty(lcInstructionsPropertyType::PLITextColor);
AddColorProperty(lcInstructionsPropertyType::PLIBorderColor);
// PLIBorderWidth,
// PLIBorderRound,
return;
}
}
lcInstructionsDialog::lcInstructionsDialog(QWidget* Parent, Project* Project)
: QMainWindow(Parent), mProject(Project)
{
setWindowTitle(tr("Instructions"));
mInstructions = mProject->GetInstructions();
mPropertiesWidget = new lcInstructionsPropertiesWidget(this, mInstructions);
mPropertiesWidget->setObjectName("InstructionsProperties");
addDockWidget(Qt::RightDockWidgetArea, mPropertiesWidget);
mPageWidget = new lcInstructionsPageWidget(this, mInstructions, mPropertiesWidget);
setCentralWidget(mPageWidget);
mPageListWidget = new lcInstructionsPageListWidget(this, mInstructions);
mPageListWidget->setObjectName("InstructionsPageList");
addDockWidget(Qt::LeftDockWidgetArea, mPageListWidget);
mPageSettingsToolBar = addToolBar(tr("Page Settings"));
mPageSettingsToolBar->setObjectName("PageSettings");
mPageSettingsToolBar->setFloatable(false);
mPageSettingsToolBar->setMovable(false);
mVerticalPageAction = mPageSettingsToolBar->addAction("Vertical");
mVerticalPageAction->setCheckable(true);
mHorizontalPageAction = mPageSettingsToolBar->addAction("Horizontal");
mHorizontalPageAction->setCheckable(true);
mRowsSpinBox = new QSpinBox(mPageSettingsToolBar);
mPageSettingsToolBar->addWidget(mRowsSpinBox);
mColumnsSpinBox = new QSpinBox(mPageSettingsToolBar);
mPageSettingsToolBar->addWidget(mColumnsSpinBox);
QActionGroup* PageDirectionGroup = new QActionGroup(mPageSettingsToolBar);
PageDirectionGroup->addAction(mVerticalPageAction);
PageDirectionGroup->addAction(mHorizontalPageAction);
for (size_t PageNumber = 0; PageNumber < mInstructions->mPages.size(); PageNumber++)
mPageListWidget->mThumbnailsWidget->addItem(QString("Page %1").arg(PageNumber + 1));
connect(mPageListWidget->mThumbnailsWidget, SIGNAL(currentRowChanged(int)), this, SLOT(CurrentThumbnailChanged(int)));
mPageListWidget->mThumbnailsWidget->setCurrentRow(0);
connect(mVerticalPageAction, SIGNAL(toggled(bool)), this, SLOT(UpdatePageSettings()));
connect(mHorizontalPageAction, SIGNAL(toggled(bool)), this, SLOT(UpdatePageSettings()));
connect(mRowsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdatePageSettings()));
connect(mColumnsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdatePageSettings()));
}
void lcInstructionsDialog::UpdatePageSettings()
{
lcInstructionsPageSettings PageSettings;
PageSettings.Rows = mRowsSpinBox->value();
PageSettings.Columns = mColumnsSpinBox->value();
if (mHorizontalPageAction->isChecked())
PageSettings.Direction = lcInstructionsDirection::Horizontal;
else
PageSettings.Direction = lcInstructionsDirection::Vertical;
mInstructions->SetDefaultPageSettings(PageSettings);
// lcInstructionsPage* Page = &mInstructions.mPages[mThumbnailsWidget->currentIndex().row()];
mPageListWidget->mThumbnailsWidget->clear();
for (size_t PageNumber = 0; PageNumber < mInstructions->mPages.size(); PageNumber++)
mPageListWidget->mThumbnailsWidget->addItem(QString("Page %1").arg(PageNumber + 1));
// mThumbnailsWidget->setCurrentRow(0);
// mPageWidget->SetCurrentPage(Page);
}
void lcInstructionsDialog::CurrentThumbnailChanged(int Index)
{
if (Index < 0 || Index >= static_cast<int>(mInstructions->mPages.size()))
{
mPageWidget->SetCurrentPage(nullptr);
return;
}
const lcInstructionsPage* Page = &mInstructions->mPages[Index];
// const lcInstructionsPageSettings& PageSettings = Page->Settings;
const lcInstructionsPageSettings& PageSettings = mInstructions->mPageSettings;
mPageWidget->SetCurrentPage(Page);
if (PageSettings.Direction == lcInstructionsDirection::Horizontal)
{
mHorizontalPageAction->blockSignals(true);
mHorizontalPageAction->setChecked(true);
mHorizontalPageAction->blockSignals(false);
}
else
{
mVerticalPageAction->blockSignals(true);
mVerticalPageAction->setChecked(true);
mVerticalPageAction->blockSignals(false);
}
mRowsSpinBox->blockSignals(true);
mRowsSpinBox->setValue(PageSettings.Rows);
mRowsSpinBox->blockSignals(false);
mColumnsSpinBox->blockSignals(true);
mColumnsSpinBox->setValue(PageSettings.Columns);
mColumnsSpinBox->blockSignals(false);
}

View file

@ -0,0 +1,182 @@
#pragma once
#include "lc_instructions.h"
class lcInstructionsPropertiesWidget;
class lcInstructionsStepImageItem : public QGraphicsPixmapItem
{
public:
lcInstructionsStepImageItem(QGraphicsItem* Parent, lcInstructions* Instructions, lcModel* Model, lcStep Step);
lcModel* GetModel() const
{
return mModel;
}
lcStep GetStep() const
{
return mStep;
}
void SetImageSize(int Width, int Height)
{
mWidth = Width;
mHeight = Height;
}
void Update();
protected:
lcInstructions* mInstructions = nullptr;
lcModel* mModel = nullptr;
lcStep mStep = 1;
int mWidth = 1;
int mHeight = 1;
};
class lcInstructionsStepNumberItem : public QGraphicsSimpleTextItem
{
public:
lcInstructionsStepNumberItem(QGraphicsItem* Parent, lcInstructions* Instructions, lcModel* Model, lcStep Step);
lcModel* GetModel() const
{
return mModel;
}
lcStep GetStep() const
{
return mStep;
}
void Update();
protected:
lcInstructions* mInstructions = nullptr;
lcModel* mModel = nullptr;
lcStep mStep = 1;
};
class lcInstructionsPartsListItem : public QGraphicsPixmapItem
{
public:
lcInstructionsPartsListItem(QGraphicsItem* Parent, lcInstructions* Instructions, lcModel* Model, lcStep Step);
lcModel* GetModel() const
{
return mModel;
}
lcStep GetStep() const
{
return mStep;
}
void Update();
protected:
lcInstructions* mInstructions = nullptr;
lcModel* mModel = nullptr;
lcStep mStep = 1;
};
class lcInstructionsPageWidget : public QGraphicsView
{
Q_OBJECT
public:
lcInstructionsPageWidget(QWidget* Parent, lcInstructions* Instructions, lcInstructionsPropertiesWidget* PropertiesWidget);
void SetCurrentPage(const lcInstructionsPage* Page);
protected slots:
void StepSettingsChanged(lcModel* Model, lcStep Step);
void SelectionChanged();
protected:
lcInstructions* mInstructions;
lcInstructionsPropertiesWidget* mPropertiesWidget;
};
class lcInstructionsPageListWidget : public QDockWidget
{
Q_OBJECT
public:
lcInstructionsPageListWidget(QWidget* Parent, lcInstructions* Instructions);
protected slots:
void ShowPageSetupDialog();
public:
//protected:
// QComboBox* mSizeComboBox = nullptr;
// QLineEdit* mWidthEdit = nullptr;
// QLineEdit* mHeightEdit = nullptr;
//
// QRadioButton* mPortraitButton = nullptr;
// QRadioButton* mLandscapeButton = nullptr;
//
// QLineEdit* mLeftMarginEdit = nullptr;
// QLineEdit* mRightMarginEdit = nullptr;
// QLineEdit* mTopMarginEdit = nullptr;
// QLineEdit* mBottomMarginEdit = nullptr;
//
// QComboBox* mUnitsComboBox = nullptr;
QListWidget* mThumbnailsWidget = nullptr;
protected:
lcInstructions* mInstructions;
};
class lcInstructionsPropertiesWidget : public QDockWidget
{
Q_OBJECT
public:
lcInstructionsPropertiesWidget(QWidget* Parent, lcInstructions* Instructions);
void SelectionChanged(QGraphicsItem* FocusItem);
protected:
void AddBoolProperty(lcInstructionsPropertyType Type);
void AddColorProperty(lcInstructionsPropertyType Type);
void AddFontProperty(lcInstructionsPropertyType Type);
lcCollapsibleWidget* mWidget = nullptr;
QGridLayout* mPropertiesLayout = nullptr;
lcInstructions* mInstructions = nullptr;
QGraphicsItem* mFocusItem = nullptr;
lcModel* mModel = nullptr;
lcStep mStep = 1;
};
class lcInstructionsDialog : public QMainWindow
{
Q_OBJECT
public:
lcInstructionsDialog(QWidget* Parent, Project* Project);
protected slots:
void UpdatePageSettings();
void CurrentThumbnailChanged(int Index);
protected:
Project* mProject = nullptr;
int mCurrentPageNumber;
lcInstructions* mInstructions;
lcInstructionsPageWidget* mPageWidget = nullptr;
lcInstructionsPageListWidget* mPageListWidget = nullptr;
lcInstructionsPropertiesWidget* mPropertiesWidget = nullptr;
QToolBar* mPageSettingsToolBar = nullptr;
QAction* mVerticalPageAction = nullptr;
QAction* mHorizontalPageAction = nullptr;
QSpinBox* mRowsSpinBox = nullptr;
QSpinBox* mColumnsSpinBox = nullptr;
};

View file

@ -16,9 +16,7 @@
#include <ctype.h>
#include <locale.h>
#include <zlib.h>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
#include <QtConcurrent>
#endif
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
@ -33,23 +31,17 @@
lcPiecesLibrary::lcPiecesLibrary()
: mLoadMutex(QMutex::Recursive)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QStringList cachePathList = QStandardPaths::standardLocations(QStandardPaths::CacheLocation);
mCachePath = cachePathList.first();
#else
mCachePath = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);
#endif
QDir Dir;
Dir.mkpath(mCachePath);
mNumOfficialPieces = 0;
mZipFiles[LC_ZIPFILE_OFFICIAL] = nullptr;
mZipFiles[LC_ZIPFILE_UNOFFICIAL] = nullptr;
mBuffersDirty = false;
mHasUnofficial = false;
mCancelLoading = false;
mStudLogo = lcGetProfileInt(LC_PROFILE_STUD_LOGO);
mStudStyle = static_cast<lcStudStyle>(lcGetProfileInt(LC_PROFILE_STUD_STYLE));
}
lcPiecesLibrary::~lcPiecesLibrary()
@ -68,19 +60,16 @@ void lcPiecesLibrary::Unload()
delete PieceIt.second;
mPieces.clear();
for (const auto& PrimitiveIt : mPrimitives)
delete PrimitiveIt.second;
mPrimitives.clear();
mSources.clear();
for (lcTexture* Texture : mTextures)
delete Texture;
mTextures.clear();
mNumOfficialPieces = 0;
delete mZipFiles[LC_ZIPFILE_OFFICIAL];
mZipFiles[LC_ZIPFILE_OFFICIAL] = nullptr;
delete mZipFiles[LC_ZIPFILE_UNOFFICIAL];
mZipFiles[LC_ZIPFILE_UNOFFICIAL] = nullptr;
for (std::unique_ptr<lcZipFile>& ZipFile : mZipFiles)
ZipFile.reset();
}
void lcPiecesLibrary::RemoveTemporaryPieces()
@ -249,29 +238,14 @@ bool lcPiecesLibrary::Load(const QString& LibraryPath, bool ShowProgress)
{
Unload();
auto LoadCustomColors = []()
if (OpenArchive(LibraryPath, lcZipFileType::Official))
{
QString CustomColorsPath = lcGetProfileString(LC_PROFILE_COLOR_CONFIG);
if (CustomColorsPath.isEmpty())
return false;
lcDiskFile ColorFile(CustomColorsPath);
return ColorFile.Open(QIODevice::ReadOnly) && lcLoadColorFile(ColorFile);
};
if (OpenArchive(LibraryPath, LC_ZIPFILE_OFFICIAL))
{
lcMemFile ColorFile;
if (!LoadCustomColors())
if (!mZipFiles[LC_ZIPFILE_OFFICIAL]->ExtractFile("ldraw/ldconfig.ldr", ColorFile) || !lcLoadColorFile(ColorFile))
lcLoadDefaultColors();
LoadColors();
mLibraryDir = QFileInfo(LibraryPath).absoluteDir();
QString UnofficialFileName = mLibraryDir.absoluteFilePath(QLatin1String("ldrawunf.zip"));
if (!OpenArchive(UnofficialFileName, LC_ZIPFILE_UNOFFICIAL))
if (!OpenArchive(UnofficialFileName, lcZipFileType::Unofficial))
UnofficialFileName.clear();
ReadArchiveDescriptions(LibraryPath, UnofficialFileName);
@ -281,59 +255,125 @@ bool lcPiecesLibrary::Load(const QString& LibraryPath, bool ShowProgress)
mLibraryDir.setPath(LibraryPath);
if (OpenDirectory(mLibraryDir, ShowProgress))
{
if (!LoadCustomColors())
{
lcDiskFile ColorFile(mLibraryDir.absoluteFilePath(QLatin1String("ldconfig.ldr")));
if (!ColorFile.Open(QIODevice::ReadOnly) || !lcLoadColorFile(ColorFile))
{
ColorFile.SetFileName(mLibraryDir.absoluteFilePath(QLatin1String("LDConfig.ldr")));
if (!ColorFile.Open(QIODevice::ReadOnly) || !lcLoadColorFile(ColorFile))
lcLoadDefaultColors();
}
}
}
LoadColors();
else
return false;
}
UpdateStudStyleSource();
lcLoadDefaultCategories();
lcSynthInit();
return true;
}
bool lcPiecesLibrary::OpenArchive(const QString& FileName, lcZipFileType ZipFileType)
void lcPiecesLibrary::LoadColors()
{
lcDiskFile* File = new lcDiskFile(FileName);
QString CustomColorsPath = lcGetProfileString(LC_PROFILE_COLOR_CONFIG);
if (!File->Open(QIODevice::ReadOnly) || !OpenArchive(File, FileName, ZipFileType))
if (!CustomColorsPath.isEmpty())
{
delete File;
return false;
lcDiskFile ColorFile(CustomColorsPath);
if (ColorFile.Open(QIODevice::ReadOnly) && lcLoadColorFile(ColorFile, mStudStyle))
{
emit ColorsLoaded();
return;
}
}
return true;
if (mZipFiles[static_cast<int>(lcZipFileType::Official)])
{
lcMemFile ColorFile;
if (!mZipFiles[static_cast<int>(lcZipFileType::Official)]->ExtractFile("ldraw/ldconfig.ldr", ColorFile) || !lcLoadColorFile(ColorFile, mStudStyle))
lcLoadDefaultColors(mStudStyle);
}
else
{
lcDiskFile ColorFile(mLibraryDir.absoluteFilePath(QLatin1String("ldconfig.ldr")));
if (!ColorFile.Open(QIODevice::ReadOnly) || !lcLoadColorFile(ColorFile, mStudStyle))
{
ColorFile.SetFileName(mLibraryDir.absoluteFilePath(QLatin1String("LDConfig.ldr")));
if (!ColorFile.Open(QIODevice::ReadOnly) || !lcLoadColorFile(ColorFile, mStudStyle))
lcLoadDefaultColors(mStudStyle);
}
}
emit ColorsLoaded();
}
bool lcPiecesLibrary::OpenArchive(lcFile* File, const QString& FileName, lcZipFileType ZipFileType)
bool lcPiecesLibrary::IsStudPrimitive(const char* FileName)
{
lcZipFile* ZipFile = new lcZipFile();
return memcmp(FileName, "STU", 3) == 0;
}
if (!ZipFile->OpenRead(File))
bool lcPiecesLibrary::IsStudStylePrimitive(const char* FileName)
{
constexpr std::array<const char*, 15> StudStylePrimitives =
{
delete ZipFile;
"2-4STUD4.DAT", "STUD.DAT", "STUD2.DAT", "STUD2A.DAT", "STUD3.DAT", "STUD4.DAT", "STUD4A.DAT", "STUD4H.DAT",
"8/STUD.DAT", "8/STUD2.DAT", "8/STUD2A.DAT", "8/STUD3.DAT", "8/STUD4.DAT", "8/STUD4A.DAT", "8/STUD4H.DAT"
};
for (const char* StudStylePrimitive : StudStylePrimitives)
if (!strcmp(StudStylePrimitive, FileName))
return true;
return false;
}
void lcPiecesLibrary::UpdateStudStyleSource()
{
if (!mSources.empty() && mSources.front()->Type == lcLibrarySourceType::StudStyle)
mSources.erase(mSources.begin());
mZipFiles[static_cast<int>(lcZipFileType::StudStyle)].reset();
if (mStudStyle == lcStudStyle::Plain)
return;
const QLatin1String FileNames[] =
{
QLatin1String(), // Plain
QLatin1String(":/resources/studlogo1.zip"), // ThinLinesLogo
QLatin1String(":/resources/studlogo2.zip"), // OutlineLogo
QLatin1String(":/resources/studlogo3.zip"), // SharpTopLogo
QLatin1String(":/resources/studlogo4.zip"), // RoundedTopLogo
QLatin1String(":/resources/studlogo5.zip"), // FlattenedLogo
QLatin1String(":/resources/studslegostyle1.zip"), // HighContrast
QLatin1String(":/resources/studslegostyle2.zip") // HighContrastLogo
};
LC_ARRAY_SIZE_CHECK(FileNames, lcStudStyle::Count);
std::unique_ptr<lcDiskFile> StudStyleFile(new lcDiskFile(FileNames[static_cast<int>(mStudStyle)]));
if (StudStyleFile->Open(QIODevice::ReadOnly))
OpenArchive(std::move(StudStyleFile), lcZipFileType::StudStyle);
}
bool lcPiecesLibrary::OpenArchive(const QString& FileName, lcZipFileType ZipFileType)
{
std::unique_ptr<lcDiskFile> File(new lcDiskFile(FileName));
if (!File->Open(QIODevice::ReadOnly))
return false;
}
mZipFiles[ZipFileType] = ZipFile;
return OpenArchive(std::move(File), ZipFileType);
}
if (ZipFileType == LC_ZIPFILE_OFFICIAL)
mLibraryFileName = FileName;
else
mUnofficialFileName = FileName;
bool lcPiecesLibrary::OpenArchive(std::unique_ptr<lcFile> File, lcZipFileType ZipFileType)
{
std::unique_ptr<lcZipFile> ZipFile(new lcZipFile());
if (!ZipFile->OpenRead(std::move(File)))
return false;
std::unique_ptr<lcLibrarySource> Source(new lcLibrarySource);
Source->Type = ZipFileType != lcZipFileType::StudStyle ? lcLibrarySourceType::Library : lcLibrarySourceType::StudStyle;
for (int FileIdx = 0; FileIdx < ZipFile->mFiles.GetSize(); FileIdx++)
{
@ -366,14 +406,14 @@ bool lcPiecesLibrary::OpenArchive(lcFile* File, const QString& FileName, lcZipFi
{
if (!memcmp(Dst, ".PNG", 4))
{
if ((ZipFileType == LC_ZIPFILE_OFFICIAL && !memcmp(Name, "LDRAW/PARTS/TEXTURES/", 21)) ||
(ZipFileType == LC_ZIPFILE_UNOFFICIAL && !memcmp(Name, "PARTS/TEXTURES/", 15)))
if ((ZipFileType == lcZipFileType::Official && !memcmp(Name, "LDRAW/PARTS/TEXTURES/", 21)) ||
(ZipFileType == lcZipFileType::Unofficial && !memcmp(Name, "PARTS/TEXTURES/", 15)))
{
lcTexture* Texture = new lcTexture();
mTextures.push_back(Texture);
*Dst = 0;
strncpy(Texture->mName, Name + (ZipFileType == LC_ZIPFILE_OFFICIAL ? 21 : 15), sizeof(Texture->mName));
strncpy(Texture->mName, Name + (ZipFileType == lcZipFileType::Official ? 21 : 15), sizeof(Texture->mName)-1);
Texture->mName[sizeof(Texture->mName) - 1] = 0;
}
}
@ -381,7 +421,7 @@ bool lcPiecesLibrary::OpenArchive(lcFile* File, const QString& FileName, lcZipFi
continue;
}
if (ZipFileType == LC_ZIPFILE_OFFICIAL)
if (ZipFileType == lcZipFileType::Official)
{
if (memcmp(Name, "LDRAW/", 6))
continue;
@ -401,7 +441,7 @@ bool lcPiecesLibrary::OpenArchive(lcFile* File, const QString& FileName, lcZipFi
{
Info = new PieceInfo();
strncpy(Info->mFileName, FileInfo.file_name + (Name - NameBuffer), sizeof(Info->mFileName));
strncpy(Info->mFileName, FileInfo.file_name + (Name - NameBuffer), sizeof(Info->mFileName)-1);
Info->mFileName[sizeof(Info->mFileName) - 1] = 0;
mPieces[Name] = Info;
@ -410,28 +450,19 @@ bool lcPiecesLibrary::OpenArchive(lcFile* File, const QString& FileName, lcZipFi
Info->SetZipFile(ZipFileType, FileIdx);
}
else
{
lcLibraryPrimitive* Primitive = FindPrimitive(Name);
if (!Primitive)
mPrimitives[Name] = new lcLibraryPrimitive(QString(), FileInfo.file_name + (Name - NameBuffer), ZipFileType, FileIdx, false, true);
else
Primitive->SetZipFile(ZipFileType, FileIdx);
}
Source->Primitives[Name] = new lcLibraryPrimitive(QString(), FileInfo.file_name + (Name - NameBuffer), ZipFileType, FileIdx, false, false, true);
}
else if (!memcmp(Name, "P/", 2))
{
Name += 2;
lcLibraryPrimitive* Primitive = FindPrimitive(Name);
if (!Primitive)
mPrimitives[Name] = new lcLibraryPrimitive(QString(), FileInfo.file_name + (Name - NameBuffer), ZipFileType, FileIdx, (memcmp(Name, "STU", 3) == 0), false);
else
Primitive->SetZipFile(ZipFileType, FileIdx);
Source->Primitives[Name] = new lcLibraryPrimitive(QString(), FileInfo.file_name + (Name - NameBuffer), ZipFileType, FileIdx, IsStudPrimitive(Name), IsStudStylePrimitive(Name), false);
}
}
mZipFiles[static_cast<int>(ZipFileType)] = std::move(ZipFile);
mSources.insert(mSources.begin(), std::move(Source));
return true;
}
@ -441,19 +472,12 @@ void lcPiecesLibrary::ReadArchiveDescriptions(const QString& OfficialFileName, c
QFileInfo UnofficialInfo(UnofficialFileName);
mArchiveCheckSum[0] = OfficialInfo.size();
#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
mArchiveCheckSum[1] = OfficialInfo.lastModified().toMSecsSinceEpoch();
#else
mArchiveCheckSum[1] = OfficialInfo.lastModified().toTime_t();
#endif
if (!UnofficialFileName.isEmpty())
{
mArchiveCheckSum[2] = UnofficialInfo.size();
#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
mArchiveCheckSum[3] = UnofficialInfo.lastModified().toMSecsSinceEpoch();
#else
mArchiveCheckSum[3] = UnofficialInfo.lastModified().toTime_t();
#endif
}
else
{
@ -471,7 +495,7 @@ void lcPiecesLibrary::ReadArchiveDescriptions(const QString& OfficialFileName, c
{
PieceInfo* Info = PieceIt.second;
mZipFiles[Info->mZipFileType]->ExtractFile(Info->mZipFileIndex, PieceFile, 256);
mZipFiles[static_cast<int>(Info->mZipFileType)]->ExtractFile(Info->mZipFileIndex, PieceFile, 256);
PieceFile.Seek(0, SEEK_END);
PieceFile.WriteU8(0);
@ -517,6 +541,9 @@ bool lcPiecesLibrary::OpenDirectory(const QDir& LibraryDir, bool ShowProgress)
for (unsigned int BaseFolderIdx = 0; BaseFolderIdx < LC_ARRAY_COUNT(BaseFolders); BaseFolderIdx++)
{
std::unique_ptr<lcLibrarySource> Source(new lcLibrarySource);
Source->Type = lcLibrarySourceType::Library;
const char* PrimitiveDirectories[] = { "p/", "parts/s/" };
bool SubFileDirectories[] = { false, false, true };
QDir BaseDir(LibraryDir.absoluteFilePath(QLatin1String(BaseFolders[BaseFolderIdx])));
@ -562,9 +589,11 @@ bool lcPiecesLibrary::OpenDirectory(const QDir& LibraryDir, bool ShowProgress)
mHasUnofficial = true;
const bool SubFile = SubFileDirectories[DirectoryIdx];
mPrimitives[Name] = new lcLibraryPrimitive(std::move(FileName), strchr(FileString, '/') + 1, LC_NUM_ZIPFILES, 0, !SubFile && (memcmp(Name, "STU", 3) == 0), SubFile);
Source->Primitives[Name] = new lcLibraryPrimitive(std::move(FileName), strchr(FileString, '/') + 1, lcZipFileType::Count, 0, !SubFile && IsStudPrimitive(Name), IsStudStylePrimitive(Name), SubFile);
}
}
mSources.push_back(std::move(Source));
}
for (unsigned int BaseFolderIdx = 0; BaseFolderIdx < LC_ARRAY_COUNT(BaseFolders); BaseFolderIdx++)
@ -707,11 +736,7 @@ void lcPiecesLibrary::ReadDirectoryDescriptions(const QFileInfoList (&FileLists)
const char* Description = FileName + strlen(FileName) + 1;
const uint64_t CachedFileTime = *(uint64_t*)(Description + strlen(Description) + 1 + 4 + 1);
#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
quint64 FileTime = FileLists[Info->mFolderType][Info->mFolderIndex].lastModified().toMSecsSinceEpoch();
#else
quint64 FileTime = FileLists[Info->mFolderType][Info->mFolderIndex].lastModified().toTime_t();
#endif
if (FileTime == CachedFileTime)
{
@ -761,19 +786,11 @@ void lcPiecesLibrary::ReadDirectoryDescriptions(const QFileInfoList (&FileLists)
while (!LoadFuture.isFinished())
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) || QT_VERSION < QT_VERSION_CHECK(5, 0, 0) )
ProgressDialog->setValue(FilesLoaded);
#else
ProgressDialog->setValue(FilesLoaded.load());
#endif
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) || QT_VERSION < QT_VERSION_CHECK(5, 0, 0) )
ProgressDialog->setValue(FilesLoaded);
#else
ProgressDialog->setValue(FilesLoaded.load());
#endif
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
ProgressDialog->deleteLater();
@ -808,11 +825,7 @@ void lcPiecesLibrary::ReadDirectoryDescriptions(const QFileInfoList (&FileLists)
NewIndexFile.WriteU8(Info->mFolderType);
#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
quint64 FileTime = FileLists[Info->mFolderType][Info->mFolderIndex].lastModified().toMSecsSinceEpoch();
#else
quint64 FileTime = FileLists[Info->mFolderType][Info->mFolderIndex].lastModified().toTime_t();
#endif
NewIndexFile.WriteU64(FileTime);
}
@ -1097,7 +1110,7 @@ bool lcPiecesLibrary::LoadCachePiece(PieceInfo* Info)
if (MeshData.ReadBuffer((char*)&Flags, sizeof(Flags)) == 0)
return false;
if (Flags != mStudLogo)
if (Flags != static_cast<qint32>(mStudStyle))
return false;
lcMesh* Mesh = new lcMesh;
@ -1117,7 +1130,7 @@ bool lcPiecesLibrary::SaveCachePiece(PieceInfo* Info)
{
lcMemFile MeshData;
const qint32 Flags = mStudLogo;
const qint32 Flags = static_cast<qint32>(mStudStyle);
if (MeshData.WriteBuffer((char*)&Flags, sizeof(Flags)) == 0)
return false;
@ -1226,17 +1239,17 @@ bool lcPiecesLibrary::LoadPieceData(PieceInfo* Info)
bool Loaded = false;
bool SaveCache = false;
if (Info->mZipFileType != LC_NUM_ZIPFILES && mZipFiles[Info->mZipFileType])
if (Info->mZipFileType != lcZipFileType::Count && mZipFiles[static_cast<int>(Info->mZipFileType)])
{
if (LoadCachePiece(Info))
return true;
lcMemFile PieceFile;
if (mZipFiles[Info->mZipFileType]->ExtractFile(Info->mZipFileIndex, PieceFile))
if (mZipFiles[static_cast<int>(Info->mZipFileType)]->ExtractFile(Info->mZipFileIndex, PieceFile))
Loaded = MeshLoader.LoadMesh(PieceFile, LC_MESHDATA_SHARED);
SaveCache = Loaded && (Info->mZipFileType == LC_ZIPFILE_OFFICIAL);
SaveCache = Loaded && (Info->mZipFileType == lcZipFileType::Official);
}
else
{
@ -1260,25 +1273,34 @@ bool lcPiecesLibrary::LoadPieceData(PieceInfo* Info)
}
}
if (!Loaded || mCancelLoading)
if (mCancelLoading)
return false;
if (Info)
Info->SetMesh(MeshData.CreateMesh());
if (Info)
{
if (Loaded)
Info->SetMesh(MeshData.CreateMesh());
else
{
lcMesh* Mesh = new lcMesh;
Mesh->CreateBox();
Info->SetMesh(Mesh);
}
}
if (SaveCache)
SaveCachePiece(Info);
return true;
return Loaded;
}
void lcPiecesLibrary::GetPrimitiveFile(lcLibraryPrimitive* Primitive, std::function<void(lcFile& File)> Callback)
{
if (mZipFiles[LC_ZIPFILE_OFFICIAL])
if (mZipFiles[static_cast<int>(lcZipFileType::Official)])
{
lcMemFile IncludeFile;
if (mZipFiles[Primitive->mZipFileType]->ExtractFile(Primitive->mZipFileIndex, IncludeFile))
if (mZipFiles[static_cast<int>(Primitive->mZipFileType)]->ExtractFile(Primitive->mZipFileIndex, IncludeFile))
Callback(IncludeFile);
}
else
@ -1298,11 +1320,11 @@ void lcPiecesLibrary::GetPieceFile(const char* PieceName, std::function<void(lcF
{
PieceInfo* Info = PieceIt->second;
if (mZipFiles[LC_ZIPFILE_OFFICIAL] && Info->mZipFileType != LC_NUM_ZIPFILES)
if (mZipFiles[static_cast<int>(lcZipFileType::Official)] && Info->mZipFileType != lcZipFileType::Count)
{
lcMemFile IncludeFile;
if (mZipFiles[Info->mZipFileType]->ExtractFile(Info->mZipFileIndex, IncludeFile))
if (mZipFiles[static_cast<int>(Info->mZipFileType)]->ExtractFile(Info->mZipFileIndex, IncludeFile))
Callback(IncludeFile);
}
else
@ -1333,31 +1355,31 @@ void lcPiecesLibrary::GetPieceFile(const char* PieceName, std::function<void(lcF
{
bool Found = false;
if (mZipFiles[LC_ZIPFILE_OFFICIAL])
if (mZipFiles[static_cast<int>(lcZipFileType::Official)])
{
lcMemFile IncludeFile;
auto LoadIncludeFile = [&IncludeFile, PieceName, this](const char* Folder, int ZipFileIndex)
auto LoadIncludeFile = [&IncludeFile, PieceName, this](const char* Folder, lcZipFileType ZipFileType)
{
char IncludeFileName[LC_MAXPATH];
sprintf(IncludeFileName, Folder, PieceName);
return mZipFiles[ZipFileIndex]->ExtractFile(IncludeFileName, IncludeFile);
return mZipFiles[static_cast<int>(ZipFileType)]->ExtractFile(IncludeFileName, IncludeFile);
};
if (mHasUnofficial)
{
Found = LoadIncludeFile("parts/%s", LC_ZIPFILE_UNOFFICIAL);
Found = LoadIncludeFile("parts/%s", lcZipFileType::Unofficial);
if (!Found)
Found = LoadIncludeFile("p/%s", LC_ZIPFILE_UNOFFICIAL);
Found = LoadIncludeFile("p/%s", lcZipFileType::Unofficial);
}
if (!Found)
{
Found = LoadIncludeFile("ldraw/parts/%s", LC_ZIPFILE_OFFICIAL);
Found = LoadIncludeFile("ldraw/parts/%s", lcZipFileType::Official);
if (!Found)
Found = LoadIncludeFile("ldraw/p/%s", LC_ZIPFILE_OFFICIAL);
Found = LoadIncludeFile("ldraw/p/%s", lcZipFileType::Official);
}
if (Found)
@ -1367,18 +1389,16 @@ void lcPiecesLibrary::GetPieceFile(const char* PieceName, std::function<void(lcF
{
lcDiskFile IncludeFile;
auto LoadIncludeFile = [&IncludeFile, PieceName, this](const char* Folder)
auto LoadIncludeFile = [&IncludeFile, PieceName, this](const QLatin1String& Folder)
{
char IncludeFileName[LC_MAXPATH];
sprintf(IncludeFileName, Folder, PieceName);
IncludeFile.SetFileName(mLibraryDir.absoluteFilePath(QLatin1String(IncludeFileName)));
const QString IncludeFileName = Folder + PieceName;
IncludeFile.SetFileName(mLibraryDir.absoluteFilePath(IncludeFileName));
if (IncludeFile.Open(QIODevice::ReadOnly))
return true;
#if defined(Q_OS_MACOS) || defined(Q_OS_LINUX)
// todo: instead of using strlwr, search the parts/primitive lists and get the file name from there
strlwr(IncludeFileName);
IncludeFile.SetFileName(mLibraryDir.absoluteFilePath(QLatin1String(IncludeFileName)));
// todo: search the parts/primitive lists and get the file name from there instead of using toLower
IncludeFile.SetFileName(mLibraryDir.absoluteFilePath(IncludeFileName.toLower()));
return IncludeFile.Open(QIODevice::ReadOnly);
#else
return false;
@ -1387,18 +1407,18 @@ void lcPiecesLibrary::GetPieceFile(const char* PieceName, std::function<void(lcF
if (mHasUnofficial)
{
Found = LoadIncludeFile("unofficial/parts/%s");
Found = LoadIncludeFile(QLatin1String("unofficial/parts/"));
if (!Found)
Found = LoadIncludeFile("unofficial/p/%s");
Found = LoadIncludeFile(QLatin1String("unofficial/p/"));
}
if (!Found)
{
Found = LoadIncludeFile("parts/%s");
Found = LoadIncludeFile(QLatin1String("parts/"));
if (!Found)
Found = LoadIncludeFile("p/%s");
Found = LoadIncludeFile(QLatin1String("p/"));
}
if (Found)
@ -1426,7 +1446,7 @@ void lcPiecesLibrary::UpdateBuffers(lcContext* Context)
for (const auto& PieceIt : mPieces)
{
const PieceInfo* const Info = PieceIt.second;
lcMesh* Mesh = Info->IsPlaceholder() ? gPlaceholderMesh : Info->GetMesh();
lcMesh* Mesh = Info->GetMesh();
if (!Mesh)
continue;
@ -1488,17 +1508,17 @@ bool lcPiecesLibrary::LoadTexture(lcTexture* Texture)
{
char FileName[2*LC_MAXPATH];
if (mZipFiles[LC_ZIPFILE_OFFICIAL])
if (mZipFiles[static_cast<int>(lcZipFileType::Official)])
{
lcMemFile TextureFile;
sprintf(FileName, "parts/textures/%s.png", Texture->mName);
if (!mZipFiles[LC_ZIPFILE_UNOFFICIAL] || !mZipFiles[LC_ZIPFILE_UNOFFICIAL]->ExtractFile(FileName, TextureFile))
if (!mZipFiles[static_cast<int>(lcZipFileType::Unofficial)] || !mZipFiles[static_cast<int>(lcZipFileType::Unofficial)]->ExtractFile(FileName, TextureFile))
{
sprintf(FileName, "ldraw/parts/textures/%s.png", Texture->mName);
if (!mZipFiles[LC_ZIPFILE_OFFICIAL]->ExtractFile(FileName, TextureFile))
if (!mZipFiles[static_cast<int>(lcZipFileType::Official)]->ExtractFile(FileName, TextureFile))
return false;
}
@ -1537,17 +1557,32 @@ void lcPiecesLibrary::UploadTextures(lcContext* Context)
mTextureUploads.clear();
}
void lcPiecesLibrary::SetStudLogo(int StudLogo, bool Reload)
bool lcPiecesLibrary::SupportsStudStyle() const
{
mStudLogo = StudLogo;
return true;
}
void lcPiecesLibrary::SetStudStyle(lcStudStyle StudStyle, bool Reload)
{
if (mStudStyle == StudStyle)
return;
mStudStyle = StudStyle;
LoadColors();
UpdateStudStyleSource();
mLoadMutex.lock();
for (const auto& PrimitiveIt : mPrimitives)
for (const std::unique_ptr<lcLibrarySource>& Source : mSources)
{
lcLibraryPrimitive* Primitive = PrimitiveIt.second;
if (Primitive->mMeshData.mHasLogoStud)
Primitive->Unload();
for (const auto& PrimitiveIt : Source->Primitives)
{
lcLibraryPrimitive* Primitive = PrimitiveIt.second;
if (Primitive->mStudStyle || Primitive->mMeshData.mHasStyleStud)
Primitive->Unload();
}
}
mLoadMutex.unlock();
@ -1560,7 +1595,7 @@ void lcPiecesLibrary::SetStudLogo(int StudLogo, bool Reload)
{
PieceInfo* Info = PieceIt.second;
if (Info->mState == LC_PIECEINFO_LOADED && Info->GetMesh() && Info->GetMesh()->mFlags & lcMeshFlag::HasLogoStud)
if (Info->mState == LC_PIECEINFO_LOADED && Info->GetMesh() && Info->GetMesh()->mFlags & lcMeshFlag::HasStyleStud)
{
Info->Unload();
mLoadQueue.append(Info);
@ -1574,84 +1609,68 @@ void lcPiecesLibrary::SetStudLogo(int StudLogo, bool Reload)
}
}
bool lcPiecesLibrary::GetStudLogoFile(lcMemFile& PrimFile, int StudLogo, bool OpenStud)
bool lcPiecesLibrary::IsPrimitive(const char* Name) const
{
// validate logo choice and unofficial lib available
if (!StudLogo || (!mZipFiles[LC_ZIPFILE_UNOFFICIAL] && !mHasUnofficial))
return false;
for (const std::unique_ptr<lcLibrarySource>& Source : mSources)
if (Source->Primitives.find(Name) != Source->Primitives.end())
return true;
// construct logo reference line
QString Logo = QString("%1").arg(StudLogo);
QString LogoRefLine = QString("1 16 0 0 0 1 0 0 0 1 0 0 0 1 ");
LogoRefLine += (OpenStud ? QString("stud2-logo%1.dat").arg(StudLogo > 1 ? Logo : ""):
QString("stud-logo%1.dat").arg(StudLogo > 1 ? Logo : ""));
return false;
}
// construct primitive file
QByteArray FileData;
QTextStream out(&FileData);
out << (OpenStud ? "0 Stud Open" : "0 Stud") << endl;
out << (OpenStud ? "0 Name: stud2.dat" : "0 Name: stud.dat") << endl;
out << "0 Author: James Jessiman" << endl;
out << "0 !LDRAW_ORG Primitive" << endl;
out << "0 BFC CERTIFY CCW" << endl;
out << LogoRefLine << endl;
lcLibraryPrimitive* lcPiecesLibrary::FindPrimitive(const char* Name) const
{
for (const std::unique_ptr<lcLibrarySource>& Source : mSources)
{
const auto PrimitiveIt = Source->Primitives.find(Name);
PrimFile.WriteBuffer(FileData.constData(), size_t(FileData.size()));
PrimFile.Seek(0, SEEK_SET);
return true;
if (PrimitiveIt != Source->Primitives.end())
return PrimitiveIt->second;
}
return nullptr;
}
bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive)
{
mLoadMutex.lock();
if (Primitive->mState == lcPrimitiveState::NOT_LOADED)
Primitive->mState = lcPrimitiveState::LOADING;
if (Primitive->mState == lcPrimitiveState::NotLoaded)
Primitive->mState = lcPrimitiveState::Loading;
else
{
mLoadMutex.unlock();
while (Primitive->mState == lcPrimitiveState::LOADING)
while (Primitive->mState == lcPrimitiveState::Loading)
lcSleeper::msleep(5);
return Primitive->mState == lcPrimitiveState::LOADED;
return Primitive->mState == lcPrimitiveState::Loaded;
}
mLoadMutex.unlock();
lcMeshLoader MeshLoader(Primitive->mMeshData, true, nullptr, false);
bool SetStudLogo = false;
if (mZipFiles[LC_ZIPFILE_OFFICIAL])
if (mZipFiles[static_cast<int>(lcZipFileType::Official)])
{
lcLibraryPrimitive* LowPrimitive = nullptr;
lcMemFile PrimFile;
if (Primitive->mStud)
if (Primitive->mStud && !Primitive->mStudStyle)
{
const bool OpenStud = !strcmp(Primitive->mName,"stud2.dat");
if (OpenStud || !strcmp(Primitive->mName,"stud.dat"))
{
Primitive->mMeshData.mHasLogoStud = true;
if (mStudLogo)
SetStudLogo = GetStudLogoFile(PrimFile, mStudLogo, OpenStud);
}
if (!SetStudLogo && strncmp(Primitive->mName, "8/", 2)) // todo: this is currently the only place that uses mName so use mFileName instead. this should also be done for the loose file libraries.
if (strncmp(Primitive->mName, "8/", 2)) // todo: this is currently the only place that uses mName so use mFileName instead. this should also be done for the loose file libraries.
{
char Name[LC_PIECE_NAME_LEN];
strcpy(Name, "8/");
strcat(Name, Primitive->mName);
strupr(Name);
LowPrimitive = FindPrimitive(Name);
LowPrimitive = FindPrimitive(Name); // todo: low primitives don't work with studlogo, because the low stud gets added as shared
}
}
if (!SetStudLogo && !mZipFiles[Primitive->mZipFileType]->ExtractFile(Primitive->mZipFileIndex, PrimFile))
if (!mZipFiles[static_cast<int>(Primitive->mZipFileType)]->ExtractFile(Primitive->mZipFileIndex, PrimFile))
return false;
if (!LowPrimitive)
@ -1664,7 +1683,7 @@ bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive)
if (!MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_HIGH))
return false;
if (!mZipFiles[LowPrimitive->mZipFileType]->ExtractFile(LowPrimitive->mZipFileIndex, PrimFile))
if (!mZipFiles[static_cast<int>(LowPrimitive->mZipFileType)]->ExtractFile(LowPrimitive->mZipFileIndex, PrimFile))
return false;
if (!MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_LOW))
@ -1673,34 +1692,27 @@ bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive)
}
else
{
if (Primitive->mStud)
{
const bool OpenStud = !strcmp(Primitive->mName,"stud2.dat");
if (OpenStud || !strcmp(Primitive->mName,"stud.dat"))
{
Primitive->mMeshData.mHasLogoStud = true;
if (mStudLogo)
{
lcMemFile PrimFile;
if (GetStudLogoFile(PrimFile, mStudLogo, OpenStud))
SetStudLogo = MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_SHARED);
}
}
}
if (!SetStudLogo)
if (Primitive->mZipFileType == lcZipFileType::Count)
{
lcDiskFile PrimFile(Primitive->mFileName);
if (!PrimFile.Open(QIODevice::ReadOnly) || !MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_SHARED)) // todo: LOD like the zip files
return false;
}
else
{
lcMemFile PrimFile;
if (!mZipFiles[static_cast<int>(Primitive->mZipFileType)]->ExtractFile(Primitive->mZipFileIndex, PrimFile))
return false;
if (!MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_SHARED))
return false;
}
}
mLoadMutex.lock();
Primitive->mState = lcPrimitiveState::LOADED;
Primitive->mState = lcPrimitiveState::Loaded;
mLoadMutex.unlock();
return true;
@ -1860,27 +1872,18 @@ std::string lcPiecesLibrary::GetPartId(const PieceInfo* Info) const
bool lcPiecesLibrary::LoadBuiltinPieces()
{
QResource Resource(":/resources/library.zip");
std::unique_ptr<lcDiskFile> File(new lcDiskFile(":/resources/library.zip"));
if (!Resource.isValid())
if (!File->Open(QIODevice::ReadOnly) || !OpenArchive(std::move(File), lcZipFileType::Official))
return false;
lcMemFile* File = new lcMemFile();
File->WriteBuffer(Resource.data(), Resource.size());
if (!OpenArchive(File, "builtin", LC_ZIPFILE_OFFICIAL))
{
delete File;
return false;
}
lcMemFile PieceFile;
for (const auto& PieceIt : mPieces)
{
PieceInfo* Info = PieceIt.second;
mZipFiles[Info->mZipFileType]->ExtractFile(Info->mZipFileIndex, PieceFile, 256);
mZipFiles[static_cast<int>(Info->mZipFileType)]->ExtractFile(Info->mZipFileIndex, PieceFile, 256);
PieceFile.Seek(0, SEEK_END);
PieceFile.WriteU8(0);
@ -1900,7 +1903,7 @@ bool lcPiecesLibrary::LoadBuiltinPieces()
}
}
lcLoadDefaultColors();
lcLoadDefaultColors(lcStudStyle::Plain);
lcLoadDefaultCategories(true);
lcSynthInit();

View file

@ -10,11 +10,30 @@ class PieceInfo;
class lcZipFile;
class lcLibraryMeshData;
enum lcZipFileType
enum class lcStudStyle
{
LC_ZIPFILE_OFFICIAL,
LC_ZIPFILE_UNOFFICIAL,
LC_NUM_ZIPFILES
Plain,
ThinLinesLogo,
OutlineLogo,
SharpTopLogo,
RoundedTopLogo,
FlattenedLogo,
HighContrast,
HighContrastLogo,
Count
};
inline bool lcIsHighContrast(lcStudStyle StudStyle)
{
return StudStyle == lcStudStyle::HighContrast || StudStyle == lcStudStyle::HighContrastLogo;
}
enum class lcZipFileType
{
Official,
Unofficial,
StudStyle,
Count
};
enum lcLibraryFolderType
@ -26,24 +45,25 @@ enum lcLibraryFolderType
enum class lcPrimitiveState
{
NOT_LOADED,
LOADING,
LOADED
NotLoaded,
Loading,
Loaded
};
class lcLibraryPrimitive
{
public:
explicit lcLibraryPrimitive(QString&& FileName, const char* Name, lcZipFileType ZipFileType, quint32 ZipFileIndex, bool Stud, bool SubFile)
explicit lcLibraryPrimitive(QString&& FileName, const char* Name, lcZipFileType ZipFileType, quint32 ZipFileIndex, bool Stud, bool StudStyle, bool SubFile)
: mFileName(std::move(FileName))
{
strncpy(mName, Name, sizeof(mName));
strncpy(mName, Name, sizeof(mName)-1);
mName[sizeof(mName) - 1] = 0;
mZipFileType = ZipFileType;
mZipFileIndex = ZipFileIndex;
mState = lcPrimitiveState::NOT_LOADED;
mState = lcPrimitiveState::NotLoaded;
mStud = Stud;
mStudStyle = StudStyle;
mSubFile = SubFile;
}
@ -55,7 +75,7 @@ public:
void Unload()
{
mState = lcPrimitiveState::NOT_LOADED;
mState = lcPrimitiveState::NotLoaded;
mMeshData.RemoveAll();
}
@ -65,10 +85,29 @@ public:
quint32 mZipFileIndex;
lcPrimitiveState mState;
bool mStud;
bool mStudStyle;
bool mSubFile;
lcLibraryMeshData mMeshData;
};
enum class lcLibrarySourceType
{
Library,
StudStyle
};
struct lcLibrarySource
{
~lcLibrarySource()
{
for (const auto& PrimitiveIt : Primitives)
delete PrimitiveIt.second;
}
lcLibrarySourceType Type;
std::map<std::string, lcLibraryPrimitive*> Primitives;
};
class lcPiecesLibrary : public QObject
{
Q_OBJECT
@ -83,6 +122,7 @@ public:
lcPiecesLibrary& operator=(lcPiecesLibrary&&) = delete;
bool Load(const QString& LibraryPath, bool ShowProgress);
void LoadColors();
void Unload();
void RemoveTemporaryPieces();
void RemovePiece(PieceInfo* Info);
@ -114,29 +154,21 @@ public:
void GetPrimitiveFile(lcLibraryPrimitive* Primitive, std::function<void(lcFile& File)> Callback);
void GetPieceFile(const char* FileName, std::function<void(lcFile& File)> Callback);
bool IsPrimitive(const char* Name) const
{
return mPrimitives.find(Name) != mPrimitives.end();
}
lcLibraryPrimitive* FindPrimitive(const char* Name) const
{
const auto PrimitiveIt = mPrimitives.find(Name);
return PrimitiveIt != mPrimitives.end() ? PrimitiveIt->second : nullptr;
}
bool IsPrimitive(const char* Name) const;
lcLibraryPrimitive* FindPrimitive(const char* Name) const;
bool LoadPrimitive(lcLibraryPrimitive* Primitive);
void SetStudLogo(int StudLogo, bool Reload);
bool SupportsStudStyle() const;
void SetStudStyle(lcStudStyle StudStyle, bool Reload);
int GetStudLogo() const
lcStudStyle GetStudStyle() const
{
return mStudLogo;
return mStudStyle;
}
void SetOfficialPieces()
{
if (mZipFiles[LC_ZIPFILE_OFFICIAL])
if (mZipFiles[static_cast<int>(lcZipFileType::Official)])
mNumOfficialPieces = (int)mPieces.size();
}
@ -150,7 +182,6 @@ public:
void UnloadUnusedParts();
std::map<std::string, PieceInfo*> mPieces;
std::map<std::string, lcLibraryPrimitive*> mPrimitives;
int mNumOfficialPieces;
std::vector<lcTexture*> mTextures;
@ -163,10 +194,11 @@ public:
signals:
void PartLoaded(PieceInfo* Info);
void ColorsLoaded();
protected:
bool OpenArchive(const QString& FileName, lcZipFileType ZipFileType);
bool OpenArchive(lcFile* File, const QString& FileName, lcZipFileType ZipFileType);
bool OpenArchive(std::unique_ptr<lcFile> File, lcZipFileType ZipFileType);
bool OpenDirectory(const QDir& LibraryDir, bool ShowProgress);
void ReadArchiveDescriptions(const QString& OfficialFileName, const QString& UnofficialFileName);
void ReadDirectoryDescriptions(const QFileInfoList (&FileLists)[LC_NUM_FOLDERTYPES], bool ShowProgress);
@ -180,7 +212,11 @@ protected:
bool ReadDirectoryCacheFile(const QString& FileName, lcMemFile& CacheFile);
bool WriteDirectoryCacheFile(const QString& FileName, lcMemFile& CacheFile);
bool GetStudLogoFile(lcMemFile& PrimFile, int StudLogo, bool OpenStud);
static bool IsStudPrimitive(const char* FileName);
static bool IsStudStylePrimitive(const char* FileName);
void UpdateStudStyleSource();
std::vector<std::unique_ptr<lcLibrarySource>> mSources;
QMutex mLoadMutex;
QList<QFuture<void>> mLoadFutures;
@ -189,14 +225,11 @@ protected:
QMutex mTextureMutex;
std::vector<lcTexture*> mTextureUploads;
int mStudLogo;
lcStudStyle mStudStyle;
QString mCachePath;
qint64 mArchiveCheckSum[4];
QString mLibraryFileName;
QString mUnofficialFileName;
lcZipFile* mZipFiles[LC_NUM_ZIPFILES];
std::unique_ptr<lcZipFile> mZipFiles[static_cast<int>(lcZipFileType::Count)];
bool mHasUnofficial;
bool mCancelLoading;
};

View file

@ -16,15 +16,10 @@ static bool lcLoadLDrawXML(std::map<int, int>& MaterialTable, std::map<int, std:
Data = File.readAll();
else
{
QResource Resource(":/resources/ldraw.xml");
QFile DefaultFile(":/resources/ldraw.xml");
if (Resource.isValid())
{
if (Resource.isCompressed())
Data = qUncompress(Resource.data(), Resource.size());
else
Data = QByteArray::fromRawData((const char*)Resource.data(), Resource.size());
}
if (DefaultFile.open(QIODevice::ReadOnly))
Data = DefaultFile.readAll();
}
if (Data.isEmpty())

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,14 @@
#pragma once
#include "lc_basewindow.h"
#include "lc_application.h"
#include "lc_shortcuts.h"
#include "lc_array.h"
#include "lc_commands.h"
#include "lc_model.h"
class View;
class lcPartSelectionWidget;
class lcPreviewDockWidget;
class PiecePreview;
class lcQGLWidget;
class lcQPartsTree;
class lcQColorList;
class lcQPropertiesTree;
@ -20,17 +20,6 @@ class QPrinter;
#define LC_MAX_RECENT_FILES 4
struct lcSearchOptions
{
bool SearchValid;
bool MatchInfo;
bool MatchColor;
bool MatchName;
PieceInfo* Info;
int ColorIndex;
char Name[256];
};
class lcTabBar : public QTabBar
{
public:
@ -46,19 +35,6 @@ protected:
int mMousePressTab;
};
class lcTabWidget : public QTabWidget
{
public:
lcTabWidget();
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
QTabBar* tabBar()
{
return QTabWidget::tabBar();
}
#endif
};
class lcModelTabWidget : public QWidget
{
Q_OBJECT
@ -83,22 +59,22 @@ public:
return Widget;
}
View* GetActiveView() const
lcView* GetActiveView() const
{
return mActiveView;
}
void SetActiveView(View* ActiveView)
void SetActiveView(lcView* ActiveView)
{
mActiveView = ActiveView;
}
void AddView(View* View)
void AddView(lcView* View)
{
mViews.Add(View);
}
void RemoveView(View* View)
void RemoveView(lcView* View)
{
if (View == mActiveView)
mActiveView = nullptr;
@ -116,15 +92,15 @@ public:
mModel = Model;
}
const lcArray<View*>* GetViews() const
const lcArray<lcView*>* GetViews() const
{
return &mViews;
}
protected:
lcModel* mModel;
View* mActiveView;
lcArray<View*> mViews;
lcView* mActiveView;
lcArray<lcView*> mViews;
};
class lcMainWindow : public QMainWindow
@ -192,7 +168,7 @@ public:
return mRelativeTransform;
}
bool GetLocalTransform() const
bool GetSeparateTransform() const
{
return mLocalTransform;
}
@ -207,7 +183,7 @@ public:
return mCurrentPieceInfo;
}
View* GetActiveView() const
lcView* GetActiveView() const
{
const lcModelTabWidget* const CurrentTab = mModelTabWidget ? (lcModelTabWidget*)mModelTabWidget->currentWidget() : nullptr;
return CurrentTab ? CurrentTab->GetActiveView() : nullptr;
@ -221,13 +197,13 @@ public:
return CurrentTab ? CurrentTab->GetModel() : nullptr;
}
const lcArray<View*>* GetViewsForModel(const lcModel* Model) const
const lcArray<lcView*>* GetViewsForModel(const lcModel* Model) const
{
const lcModelTabWidget* const TabWidget = GetTabWidgetForModel(Model);
return TabWidget ? TabWidget->GetViews() : nullptr;
}
lcModelTabWidget* GetTabForView(View* View) const
lcModelTabWidget* GetTabForView(lcView* View) const
{
for (int TabIdx = 0; TabIdx < mModelTabWidget->count(); TabIdx++)
{
@ -246,6 +222,11 @@ public:
return mPartSelectionWidget;
}
lcPreviewDockWidget* GetPreviewWidget() const
{
return mPreviewWidget;
}
QMenu* GetToolsMenu() const
{
return mToolsMenu;
@ -277,10 +258,8 @@ public:
void CloseCurrentModelTab();
void SetCurrentModelTab(lcModel* Model);
void ResetCameras();
void AddView(View* View);
void RemoveView(View* View);
void SetActiveView(View* ActiveView);
void UpdateAllViews();
void AddView(lcView* View);
void RemoveView(lcView* View);
void SetTool(lcTool Tool);
void SetTransformType(lcTransformType TransformType);
@ -291,11 +270,13 @@ public:
void SetMoveZSnapIndex(int Index);
void SetAngleSnapIndex(int Index);
void SetRelativeTransform(bool RelativeTransform);
void SetLocalTransform(bool SelectionTransform);
void SetSeparateTransform(bool SelectionTransform);
void SetCurrentPieceInfo(PieceInfo* Info);
void SetShadingMode(lcShadingMode ShadingMode);
void SetSelectionMode(lcSelectionMode SelectionMode);
void ToggleViewSphere();
void ToggleAxisIcon();
void ToggleGrid();
void ToggleFadePreviousSteps();
void NewProject();
@ -330,7 +311,6 @@ public:
void UpdateSnap();
void UpdateColor();
void UpdateUndoRedo(const QString& UndoText, const QString& RedoText);
void UpdateCurrentCamera(int CameraIndex);
void UpdatePerspective();
void UpdateCameraMenu();
void UpdateShadingMode();
@ -346,13 +326,17 @@ public:
QString mRecentFiles[LC_MAX_RECENT_FILES];
int mColorIndex;
lcSearchOptions mSearchOptions;
QAction* mActions[LC_NUM_COMMANDS];
public slots:
void ProjectFileChanged(const QString& Path);
void PreviewPiece(const QString& PartId, int ColorCode, bool ShowPreview);
void TogglePreviewWidget(bool Visible);
protected slots:
void ViewFocusReceived();
void ViewCameraChanged();
void UpdateDockWidgetActions();
void UpdateGamepads();
void ModelTabContextMenuRequested(const QPoint& Point);
void ModelTabCloseOtherTabs();
@ -361,7 +345,9 @@ protected slots:
void ClipboardChanged();
void ActionTriggered();
void ColorChanged(int ColorIndex);
void ColorButtonClicked();
void Print(QPrinter* Printer);
void EnableWindowFlags(bool);
protected:
void closeEvent(QCloseEvent *event) override;
@ -373,13 +359,17 @@ protected:
void CreateMenus();
void CreateToolBars();
void CreateStatusBar();
lcView* CreateView(lcModel* Model);
void SetActiveView(lcView* ActiveView);
void ToggleDockWidget(QWidget* DockWidget);
void SplitView(Qt::Orientation Orientation);
void ShowSearchDialog();
void ShowUpdatesDialog();
void ShowAboutDialog();
void ShowHTMLDialog();
void ShowRenderDialog();
void ShowInstructionsDialog();
void ShowPrintDialog();
void CreatePreviewWidget();
bool OpenProjectFile(const QString& FileName);
@ -415,10 +405,11 @@ protected:
QAction* mActionFileRecentSeparator;
lcTabWidget* mModelTabWidget;
QTabWidget* mModelTabWidget;
QToolBar* mStandardToolBar;
QToolBar* mToolsToolBar;
QToolBar* mTimeToolBar;
QDockWidget* mPreviewToolBar;
QDockWidget* mPartsToolBar;
QDockWidget* mColorsToolBar;
QDockWidget* mPropertiesToolBar;
@ -426,17 +417,20 @@ protected:
lcPartSelectionWidget* mPartSelectionWidget;
lcQColorList* mColorList;
QToolButton* mColorButton;
lcQPropertiesTree* mPropertiesWidget;
lcTimelineWidget* mTimelineWidget;
QLineEdit* mTransformXEdit;
QLineEdit* mTransformYEdit;
QLineEdit* mTransformZEdit;
lcPreviewDockWidget* mPreviewWidget;
lcElidedLabel* mStatusBarLabel;
QLabel* mStatusPositionLabel;
QLabel* mStatusSnapLabel;
QLabel* mStatusTimeLabel;
QMenu* mTransformMenu;
QMenu* mToolsMenu;
QMenu* mViewpointMenu;
QMenu* mCameraMenu;

View file

@ -7,14 +7,26 @@
#define LC_RTOD (static_cast<float>(180 / M_PI))
#define LC_PI (static_cast<float>(M_PI))
#define LC_2PI (static_cast<float>(2 * M_PI))
#define LC_RGB_EPSILON (static_cast<float>(0.5f / 255.0f))
#define LC_RGB(r,g,b) LC_RGBA(r,g,b,255)
#define LC_RGBA(r,g,b,a) ((quint32)(((quint8) (r) | ((quint16) (g) << 8)) | (((quint32) (quint8) (b)) << 16) | (((quint32) (quint8) (a)) << 24)))
#define LC_RGBA(r,g,b,a) ((quint32)(((quint8) (r) | ((quint16) (g) << 8)) | (((quint32) (quint8) (b)) << 16) | (((quint32) (quint8) (a)) << 24)))
#define LC_RGBA_RED(rgba) ((quint8)(((rgba) >> 0) & 0xff))
#define LC_RGBA_GREEN(rgba) ((quint8)(((rgba) >> 8) & 0xff))
#define LC_RGBA_BLUE(rgba) ((quint8)(((rgba) >> 16) & 0xff))
#define LC_RGBA_ALPHA(rgba) ((quint8)(((rgba) >> 24) & 0xff))
#define LC_FLOATRGB(f) LC_RGB(f[0]*255, f[1]*255, f[2]*255)
#define LC_SRGB_TO_LINEAR(v) (powf(v, 2.2f))
#define LC_LINEAR_TO_SRGB(v) (powf(v, 1.0f / 2.2f))
inline quint32 lcRGBAFromQColor(const QColor& Color)
{
return LC_RGBA(Color.red(), Color.green(), Color.blue(), Color.alpha());
}
inline QColor lcQColorFromRGBA(quint32 RGBA)
{
return QColor::fromRgb(LC_RGBA_RED(RGBA), LC_RGBA_GREEN(RGBA), LC_RGBA_BLUE(RGBA), LC_RGBA_ALPHA(RGBA));
}
template<typename T>
inline T lcMin(const T& a, const T& b)
@ -55,12 +67,12 @@ public:
{
return (const float*)this;
}
operator float*()
{
return (float*)this;
}
const float& operator[](int i) const
{
return ((float*)this)[i];
@ -97,12 +109,12 @@ public:
{
return (const float*)this;
}
operator float*()
{
return (float*)this;
}
const float& operator[](int i) const
{
return ((float*)this)[i];
@ -146,12 +158,12 @@ public:
{
return (const float*)this;
}
operator float*()
{
return (float*)this;
}
const float& operator[](int i) const
{
return ((float*)this)[i];
@ -190,12 +202,12 @@ public:
{
return (const float*)this;
}
operator float*()
{
return (float*)this;
}
const lcVector3& operator[](int i) const
{
return r[i];
@ -248,12 +260,12 @@ public:
{
return (const float*)this;
}
operator float*()
{
return (float*)this;
}
const lcVector4& operator[](int i) const
{
return r[i];
@ -355,6 +367,15 @@ inline lcVector3& operator/=(lcVector3& a, const lcVector3& b)
return a;
}
inline lcVector3& operator+=(lcVector3& a, float b)
{
a.x += b;
a.y += b;
a.z += b;
return a;
}
inline lcVector3& operator*=(lcVector3& a, float b)
{
a.x *= b;
@ -637,7 +658,30 @@ inline lcVector4 lcVector4FromColor(quint32 Color)
inline quint32 lcColorFromVector3(const lcVector3& Color)
{
return LC_RGB(Color[0] * 255, Color[1] * 255, Color[2] * 255);
return LC_RGB(roundf(Color[0] * 255), roundf(Color[1] * 255), roundf(Color[2] * 255));
}
inline float lcLuminescence(const lcVector3& Color)
{
return 0.2126f * Color[0] + 0.7152f * Color[1] + 0.0722f * Color[2];
}
inline lcVector3 lcSRGBToLinear(const lcVector3& Color)
{
const float r = LC_SRGB_TO_LINEAR(Color[0]);
const float g = LC_SRGB_TO_LINEAR(Color[1]);
const float b = LC_SRGB_TO_LINEAR(Color[2]);
return lcVector3(r, g, b);
}
inline lcVector3 lcLinearToSRGB(const lcVector3& Color)
{
const float r = LC_LINEAR_TO_SRGB(Color[0]);
const float g = LC_LINEAR_TO_SRGB(Color[1]);
const float b = LC_LINEAR_TO_SRGB(Color[2]);
return lcVector3(r, g, b);
}
inline lcVector3 lcMul(const lcVector3& a, const lcMatrix33& b)
@ -1212,7 +1256,7 @@ inline lcVector3 lcMatrix44ToEulerAngles(const lcMatrix44& RotMat)
CosRoll = RotMat.r[2][2] / CosPitch;
SinYaw = RotMat.r[0][1] / CosPitch;
CosYaw = RotMat.r[0][0] / CosPitch;
}
}
else
{
SinRoll = -RotMat.r[2][1];
@ -1362,9 +1406,9 @@ inline lcMatrix44 lcMatrix44Inverse(const lcMatrix44& m)
const lcVector4 Row1(r0[5], r1[5], r2[5], r3[5]);
const lcVector4 Row2(r0[6], r1[6], r2[6], r3[6]);
const lcVector4 Row3(r0[7], r1[7], r2[7], r3[7]);
lcMatrix44 out(Row0, Row1, Row2, Row3);
return out;
#undef MAT
@ -1562,7 +1606,7 @@ inline void lcGetFrustumPlanes(const lcMatrix44& WorldView, const lcMatrix44& Pr
}
}
inline std::tuple<lcVector3, float> lcZoomExtents(const lcVector3& Position, const lcMatrix44& WorldView, const lcMatrix44& Projection, const lcVector3* Points, int NumPoints)
inline std::tuple<lcVector3, float> lcZoomExtents(const lcVector3& Position, const lcMatrix44& WorldView, const lcMatrix44& Projection, const lcVector3* Points, size_t NumPoints)
{
if (!NumPoints)
return std::make_tuple(Position, 2500.0f);
@ -1580,7 +1624,7 @@ inline std::tuple<lcVector3, float> lcZoomExtents(const lcVector3& Position, con
const float ep = lcDot(Position, Plane);
const float fp = lcDot(Front, Plane);
for (int PointIdx = 0; PointIdx < NumPoints; PointIdx++)
for (size_t PointIdx = 0; PointIdx < NumPoints; PointIdx++)
{
const float u = (ep - lcDot(Points[PointIdx], Plane)) / fp;
@ -1593,7 +1637,7 @@ inline std::tuple<lcVector3, float> lcZoomExtents(const lcVector3& Position, con
float FarDistance = 2500.0f;
for (int PointIdx = 0; PointIdx < NumPoints; PointIdx++)
for (size_t PointIdx = 0; PointIdx < NumPoints; PointIdx++)
{
const float Distance = lcDot(Points[PointIdx], Front);
@ -1987,7 +2031,7 @@ inline bool lcBoundingBoxIntersectsVolume(const lcVector3& Min, const lcVector3&
if (OutcodesOR == 0)
return true;
int Indices[36] =
int Indices[36] =
{
0, 1, 2,
0, 2, 3,
@ -2043,3 +2087,128 @@ bool SphereIntersectsVolume(const Vector3& Center, float Radius, const Vector4*
return true;
}*/
inline lcVector3 lcRGBToHSL(const lcVector3& rgb)
{
int Mi;
float M, m, C, h, S, L; // h is H/60
Mi = (rgb[0] >= rgb[1]) ? 0 : 1;
Mi = (rgb[Mi] >= rgb[2]) ? Mi : 2;
M = rgb[Mi];
m = (rgb[0] < rgb[1]) ? rgb[0] : rgb[1];
m = (m < rgb[2]) ? m : rgb[2];
C = M - m;
L = (M + m) / 2.0f;
if (C < LC_RGB_EPSILON) // C == 0.0
h = 0.0f;
else if (Mi == 0) // M == R
h = 0.0f + (rgb[1] - rgb[2]) / C;
else if (Mi == 1) // M == G
h = 2.0f + (rgb[2] - rgb[0]) / C;
else // M = B
h = 4.0f + (rgb[0] - rgb[1]) / C;
h = (h < 0.0) ? h + 6.0f : h;
h = (h >= 6.0) ? h - 6.0f : h;
S = ((L < (LC_RGB_EPSILON / 2.0f)) || (L > (1.0f -(LC_RGB_EPSILON / 2.0f))))
? 0.0f : (2.0f * (M - L)) / (1.0f - fabs((2.0f * L) - 1.0f)) ;
return lcVector3(h, S, L);
}
inline lcVector3 lcHSLToRGB(const lcVector3& hSL)
{
lcVector3 rgb;
float h, S, L, C, X, m;
h = hSL[0];
S = hSL[1];
L = hSL[2];
C = (1.0f - fabs(2.0f * L - 1.0f)) * S;
X = C * (1.0f - fabs(fmodf(h, 2.0f) - 1.0f));
if (h < 1.0f)
rgb = lcVector3(C, X, 0.0f);
else if (h < 2.0f)
rgb = lcVector3(X, C, 0.0f);
else if (h < 3.0f)
rgb = lcVector3(0.0f, C, X);
else if (h < 4.0f)
rgb = lcVector3(0.0f, X, C);
else if (h < 5.0f)
rgb = lcVector3(X, 0.0f, C);
else
rgb = lcVector3(C, 0.0f, X);
m = L - C / 2.0f;
rgb += m;
return rgb;
}
inline lcVector4 lcAlgorithmicEdgeColor(const lcVector3& Value, const float ValueLum, const float EdgeLum, const float Contrast, const float Saturation)
{
float y1, yt;
lcVector3 hSL, rgb1, rgbf;
// Determine luma target
if (EdgeLum < ValueLum)
{
// Light base color
yt = ValueLum - Contrast * ValueLum;
}
else
{
// Dark base color
yt = ValueLum + Contrast * (1.0f - ValueLum);
}
// Get base color in hSL
hSL = lcRGBToHSL(Value);
// Adjust saturation
// sat = 4.0f * sat - 2.0f;
// if (sat < 0.0f)
// {
// sat = -sat;
// hSL[0] = (hSL[0] < 3.0f) ? hSL[0] + 3.0f : hSL[0] - 3.0f;
// }
// sat = (sat > 2.0f) ? 2.0f : sat;
// if (sat > 1.0f)
// {
// // Supersaturate
// sat -= 1.0f;
// hSL[1] += sat * (1.0f - hSL[1]);
// }
// else
// {
// Desaturate
hSL[1] *= Saturation;
// }
// Adjusted color to RGB
rgb1 = lcHSLToRGB(lcVector3(hSL[0], hSL[1], 0.5f));
// Fix adjusted color luma to target value
y1 = lcLuminescence(rgb1);
if (yt < y1)
{
// Make darker via scaling
rgbf = (yt/y1) * rgb1;
}
else
{
// Make lighter via scaling anti-color
rgbf = lcVector3(1.0f, 1.0f, 1.0f) - rgb1;
rgbf *= (1.0f - yt) / (1.0f - y1);
rgbf = lcVector3(1.0f, 1.0f, 1.0f) - rgbf;
}
return lcVector4(lcLinearToSRGB(rgbf), 1.0f);
}

View file

@ -29,7 +29,6 @@ lcMesh::lcMesh()
mIndexDataSize = 0;
mVertexCacheOffset = -1;
mIndexCacheOffset = -1;
mFlags = 0;
}
lcMesh::~lcMesh()
@ -493,10 +492,10 @@ bool lcMesh::FileSave(lcMemFile& File)
int lcMesh::GetLodIndex(float Distance) const
{
if (lcGetPiecesLibrary()->GetStudLogo())
if (lcGetPiecesLibrary()->GetStudStyle() != lcStudStyle::Plain) // todo: support low lod studs
return LC_MESH_LOD_HIGH;
if (mLods[LC_MESH_LOD_LOW].NumSections && (Distance - mRadius) > 250.0f)
if (mLods[LC_MESH_LOD_LOW].NumSections && (Distance > mRadius))
return LC_MESH_LOD_LOW;
else
return LC_MESH_LOD_HIGH;

View file

@ -48,18 +48,14 @@ enum
LC_NUM_MESH_LODS
};
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
enum class lcMeshFlag
#else
enum lcMeshFlag
#endif
{
HasDefault = 0x01, // Mesh has triangles using the default color
HasSolid = 0x02, // Mesh has triangles using a solid color
HasTranslucent = 0x04, // Mesh has triangles using a translucent color
HasLines = 0x08, // Mesh has lines
HasTexture = 0x10, // Mesh has sections using textures
HasLogoStud = 0x20 // Mesh has a stud that can have a logo applied
HasStyleStud = 0x20 // Mesh has a stud that can have a logo applied
};
Q_DECLARE_FLAGS(lcMeshFlags, lcMeshFlag)
@ -117,5 +113,4 @@ public:
int mIndexType;
};
extern lcMesh* gPlaceholderMesh;

View file

@ -1187,8 +1187,8 @@ lcMesh* lcLibraryMeshData::CreateMesh()
}
}
if (mHasLogoStud)
Mesh->mFlags |= lcMeshFlag::HasLogoStud;
if (mHasStyleStud)
Mesh->mFlags |= lcMeshFlag::HasStyleStud;
lcVector3 MeshMin(FLT_MAX, FLT_MAX, FLT_MAX), MeshMax(-FLT_MAX, -FLT_MAX, -FLT_MAX);
bool UpdatedBoundingBox = false;
@ -1610,7 +1610,7 @@ bool lcMeshLoader::ReadMeshData(lcFile& File, const lcMatrix44& CurrentTransform
if (Primitive)
{
if (Primitive->mState != lcPrimitiveState::LOADED && !Library->LoadPrimitive(Primitive))
if (Primitive->mState != lcPrimitiveState::Loaded && !Library->LoadPrimitive(Primitive))
break;
if (Primitive->mStud)
@ -1625,7 +1625,7 @@ bool lcMeshLoader::ReadMeshData(lcFile& File, const lcMatrix44& CurrentTransform
else
Library->GetPrimitiveFile(Primitive, FileCallback);
mMeshData.mHasLogoStud |= Primitive->mMeshData.mHasLogoStud;
mMeshData.mHasStyleStud |= Primitive->mStudStyle | Primitive->mMeshData.mHasStyleStud;
}
else
Library->GetPieceFile(FileName, FileCallback);

View file

@ -93,7 +93,7 @@ public:
lcLibraryMeshData()
{
mHasTextures = false;
mHasLogoStud = false;
mHasStyleStud = false;
for (int MeshDataIdx = 0; MeshDataIdx < LC_NUM_MESHDATA_TYPES; MeshDataIdx++)
mVertices[MeshDataIdx].SetGrow(1024);
@ -148,7 +148,7 @@ public:
lcArray<lcLibraryMeshSection*> mSections[LC_NUM_MESHDATA_TYPES];
lcArray<lcLibraryMeshVertex> mVertices[LC_NUM_MESHDATA_TYPES];
bool mHasTextures;
bool mHasLogoStud;
bool mHasStyleStud;
};
class lcMeshLoader

280
common/lc_minifigdialog.cpp Normal file
View file

@ -0,0 +1,280 @@
#include "lc_global.h"
#include "lc_minifigdialog.h"
#include "ui_lc_minifigdialog.h"
#include "lc_viewwidget.h"
#include "lc_qcolorpicker.h"
#include "minifig.h"
#include "lc_application.h"
#include "pieceinf.h"
#include "lc_library.h"
#include "lc_view.h"
#include "camera.h"
lcMinifigDialog::lcMinifigDialog(QWidget* Parent)
: QDialog(Parent), ui(new Ui::lcMinifigDialog)
{
ui->setupUi(this);
mComboBoxes =
{
ui->hatsType, ui->hats2Type, ui->headType, ui->neckType, ui->bodyType, ui->body2Type, ui->body3Type, ui->rarmType, ui->larmType,
ui->rhandType, ui->lhandType, ui->rhandaType, ui->lhandaType, ui->rlegType, ui->llegType, ui->rlegaType, ui->llegaType
};
mColorPickers =
{
ui->hatsColor, ui->hats2Color, ui->headColor, ui->neckColor, ui->bodyColor, ui->body2Color, ui->body3Color, ui->rarmColor, ui->larmColor,
ui->rhandColor, ui->lhandColor, ui->rhandaColor, ui->lhandaColor, ui->rlegColor, ui->llegColor, ui->rlegaColor, ui->llegaColor
};
mSpinBoxes =
{
ui->hatsAngle, ui->hats2Angle, ui->headAngle, nullptr, nullptr, nullptr, nullptr, ui->rarmAngle, ui->larmAngle,
ui->rhandAngle, ui->lhandAngle, ui->rhandaAngle, ui->lhandaAngle, ui->rlegAngle, ui->llegAngle, ui->rlegaAngle, ui->llegaAngle
};
for (QComboBox* ComboBox : mComboBoxes)
connect(ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(TypeChanged(int)));
for (lcQColorPicker* ColorPicker : mColorPickers)
connect(ColorPicker, SIGNAL(colorChanged(int)), this, SLOT(ColorChanged(int)));
for (QDoubleSpinBox* SpinBox : mSpinBoxes)
if (SpinBox)
connect(SpinBox, SIGNAL(valueChanged(double)), this, SLOT(AngleChanged(double)));
QGridLayout* PreviewLayout = new QGridLayout(ui->minifigFrame);
PreviewLayout->setContentsMargins(0, 0, 0, 0);
mMinifigWizard = new MinifigWizard();
mView = new lcView(lcViewType::Minifig, mMinifigWizard->GetModel());
lcViewWidget* ViewWidget = new lcViewWidget(nullptr, mView);
ViewWidget->setMinimumWidth(100);
PreviewLayout->addWidget(ViewWidget);
mView->MakeCurrent();
mMinifigWizard->LoadDefault();
for (int ItemIndex = 0; ItemIndex < LC_MFW_NUMITEMS; ItemIndex++)
{
const std::vector<lcMinifigPieceInfo>& PartList = mMinifigWizard->mSettings[ItemIndex];
QStringList ItemStrings;
QVector<int> Separators;
for (const lcMinifigPieceInfo& MinifigPieceInfo : PartList)
{
const char* Description = MinifigPieceInfo.Description;
if (Description[0] != '-' || Description[1] != '-')
ItemStrings.append(Description);
else
Separators.append(ItemStrings.size());
}
QComboBox* ItemCombo = mComboBoxes[ItemIndex];
ItemCombo->blockSignals(true);
ItemCombo->addItems(ItemStrings);
for (int SeparatorIndex = Separators.size() - 1; SeparatorIndex >= 0; SeparatorIndex--)
ItemCombo->insertSeparator(Separators[SeparatorIndex]);
ItemCombo->setCurrentIndex(mMinifigWizard->GetSelectionIndex(ItemIndex));
ItemCombo->blockSignals(false);
lcQColorPicker* ColorPicker = mColorPickers[ItemIndex];
ColorPicker->blockSignals(true);
ColorPicker->setCurrentColor(mMinifigWizard->mMinifig.Colors[ItemIndex]);
ColorPicker->blockSignals(false);
}
UpdateTemplateCombo();
mMinifigWizard->Calculate();
mView->GetCamera()->SetViewpoint(lcVector3(0.0f, -270.0f, 90.0f));
mView->ZoomExtents();
}
lcMinifigDialog::~lcMinifigDialog()
{
delete mMinifigWizard;
delete ui;
}
void lcMinifigDialog::UpdateTemplateCombo()
{
ui->TemplateComboBox->clear();
const auto& Templates = mMinifigWizard->GetTemplates();
for (const auto& Template : Templates)
ui->TemplateComboBox->addItem(Template.first);
}
void lcMinifigDialog::on_TemplateComboBox_currentIndexChanged(const QString& TemplateName)
{
const auto& Templates = mMinifigWizard->GetTemplates();
const auto& Position = Templates.find(TemplateName);
if (Position == Templates.end())
return;
const lcMinifigTemplate& Template = Position->second;
for (int PartIdx = 0; PartIdx < LC_MFW_NUMITEMS; PartIdx++)
{
if (!Template.Parts[PartIdx].isEmpty())
{
PieceInfo* Info = lcGetPiecesLibrary()->FindPiece(Template.Parts[PartIdx].toLatin1(), nullptr, false, false);
if (Info)
{
for (const lcMinifigPieceInfo& MinifigPieceInfo : mMinifigWizard->mSettings[PartIdx])
{
if (Info == MinifigPieceInfo.Info)
{
mComboBoxes[PartIdx]->setCurrentText(MinifigPieceInfo.Description);
break;
}
}
}
}
else
{
mComboBoxes[PartIdx]->setCurrentText("None");
}
mColorPickers[PartIdx]->setCurrentColorCode(Template.Colors[PartIdx]);
QDoubleSpinBox* AngleSpinBox = mSpinBoxes[PartIdx];
if (AngleSpinBox)
AngleSpinBox->setValue(Template.Angles[PartIdx]);
}
mMinifigWizard->Calculate();
}
void lcMinifigDialog::on_TemplateSaveButton_clicked()
{
QString CurrentName = ui->TemplateComboBox->currentText();
bool Ok;
QString TemplateName = QInputDialog::getText(this, tr("Save Template"), tr("Template Name:"), QLineEdit::Normal, CurrentName, &Ok);
if (!Ok)
return;
if (TemplateName.isEmpty())
{
QMessageBox::information(this, tr("Save Template"), tr("Template name cannot be empty."));
return;
}
if (TemplateName == CurrentName)
{
QString Question = tr("Are you sure you want to overwrite the template '%1'?").arg(TemplateName);
if (QMessageBox::question(this, tr("Overwrite Template"), Question, QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
return;
}
lcMinifigTemplate Template;
for (int PartIdx = 0; PartIdx < LC_MFW_NUMITEMS; PartIdx++)
{
Template.Parts[PartIdx] = mMinifigWizard->mSettings[PartIdx][mComboBoxes[PartIdx]->currentIndex()].Info->mFileName;
Template.Colors[PartIdx] = mColorPickers[PartIdx]->currentColorCode();
QDoubleSpinBox* AngleSpinBox = mSpinBoxes[PartIdx];
Template.Angles[PartIdx] = AngleSpinBox ? AngleSpinBox->value() : 0.0f;
}
mMinifigWizard->SaveTemplate(TemplateName, Template);
ui->TemplateComboBox->blockSignals(true);
UpdateTemplateCombo();
ui->TemplateComboBox->setCurrentText(TemplateName);
ui->TemplateComboBox->blockSignals(false);
}
void lcMinifigDialog::on_TemplateDeleteButton_clicked()
{
QString Template = ui->TemplateComboBox->currentText();
QString Question = tr("Are you sure you want to delete the template '%1'?").arg(Template);
if (QMessageBox::question(this, tr("Delete Template"), Question, QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
return;
mMinifigWizard->DeleteTemplate(Template);
UpdateTemplateCombo();
}
void lcMinifigDialog::on_TemplateImportButton_clicked()
{
QString FileName = QFileDialog::getOpenFileName(this, tr("Import Templates"), "", tr("Minifig Template Files (*.minifig);;All Files (*.*)"));
if (FileName.isEmpty())
return;
QFile File(FileName);
if (!File.open(QIODevice::ReadOnly))
{
QMessageBox::warning(this, tr("Error"), tr("Error reading file '%1':\n%2").arg(FileName, File.errorString()));
return;
}
QByteArray FileData = File.readAll();
mMinifigWizard->AddTemplatesJson(FileData);
UpdateTemplateCombo();
}
void lcMinifigDialog::on_TemplateExportButton_clicked()
{
QString FileName = QFileDialog::getSaveFileName(this, tr("Export Templates"), "", tr("Minifig Template Files (*.minifig);;All Files (*.*)"));
if (FileName.isEmpty())
return;
QFile File(FileName);
if (!File.open(QIODevice::WriteOnly))
{
QMessageBox::warning(this, tr("Error"), tr("Error writing to file '%1':\n%2").arg(FileName, File.errorString()));
return;
}
QByteArray Templates = mMinifigWizard->GetTemplatesJson();
File.write(Templates);
}
void lcMinifigDialog::TypeChanged(int Index)
{
std::array<QComboBox*, LC_MFW_NUMITEMS>::iterator Search = std::find(mComboBoxes.begin(), mComboBoxes.end(), sender());
if (Search == mComboBoxes.end())
return;
mView->MakeCurrent();
mMinifigWizard->SetSelectionIndex(std::distance(mComboBoxes.begin(), Search), Index);
mView->Redraw();
}
void lcMinifigDialog::ColorChanged(int Index)
{
std::array<lcQColorPicker*, LC_MFW_NUMITEMS>::iterator Search = std::find(mColorPickers.begin(), mColorPickers.end(), sender());
if (Search == mColorPickers.end())
return;
mMinifigWizard->SetColor(std::distance(mColorPickers.begin(), Search), Index);
mView->Redraw();
}
void lcMinifigDialog::AngleChanged(double Value)
{
std::array<QDoubleSpinBox*, LC_MFW_NUMITEMS>::iterator Search = std::find(mSpinBoxes.begin(), mSpinBoxes.end(), sender());
if (Search == mSpinBoxes.end())
return;
mMinifigWizard->SetAngle(std::distance(mSpinBoxes.begin(), Search), Value);
mView->Redraw();
}

40
common/lc_minifigdialog.h Normal file
View file

@ -0,0 +1,40 @@
#pragma once
#include "minifig.h"
class lcQColorPicker;
namespace Ui
{
class lcMinifigDialog;
}
class lcMinifigDialog : public QDialog
{
Q_OBJECT
public:
explicit lcMinifigDialog(QWidget* Parent);
~lcMinifigDialog();
MinifigWizard* mMinifigWizard;
protected slots:
void on_TemplateComboBox_currentIndexChanged(const QString& TemplateName);
void on_TemplateSaveButton_clicked();
void on_TemplateDeleteButton_clicked();
void on_TemplateImportButton_clicked();
void on_TemplateExportButton_clicked();
void TypeChanged(int Index);
void ColorChanged(int Index);
void AngleChanged(double Value);
protected:
void UpdateTemplateCombo();
Ui::lcMinifigDialog* ui;
lcView* mView;
std::array<QComboBox*, LC_MFW_NUMITEMS> mComboBoxes;
std::array<lcQColorPicker*, LC_MFW_NUMITEMS> mColorPickers;
std::array<QDoubleSpinBox*, LC_MFW_NUMITEMS> mSpinBoxes;
};

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>lcQMinifigDialog</class>
<widget class="QDialog" name="lcQMinifigDialog">
<class>lcMinifigDialog</class>
<widget class="QDialog" name="lcMinifigDialog">
<property name="geometry">
<rect>
<x>0</x>
@ -26,7 +26,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -68,7 +68,7 @@
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::Panel</enum>
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
@ -110,7 +110,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -126,7 +126,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -168,7 +168,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -198,7 +198,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -214,7 +214,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -282,7 +282,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -298,7 +298,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -366,7 +366,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -382,7 +382,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -450,7 +450,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -466,7 +466,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -496,7 +496,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -512,7 +512,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -580,7 +580,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -596,7 +596,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -664,7 +664,7 @@
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="minimumContentsLength">
<number>24</number>
@ -803,7 +803,7 @@
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>lcQMinifigDialog</receiver>
<receiver>lcMinifigDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
@ -819,7 +819,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>lcQMinifigDialog</receiver>
<receiver>lcMinifigDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
#pragma once
#include "lc_math.h"
#include "object.h"
#include "lc_commands.h"
#include "lc_array.h"
#define LC_SEL_NO_PIECES 0x0001 // No pieces in model
#define LC_SEL_PIECE 0x0002 // At last 1 piece selected
@ -18,8 +18,6 @@
#define LC_SEL_CAN_ADD_CONTROL_POINT 0x0800 // Can add control points to focused piece
#define LC_SEL_CAN_REMOVE_CONTROL_POINT 0x1000 // Can remove control points from focused piece
class lcGLWidget;
enum class lcSelectionMode
{
Single,
@ -38,30 +36,18 @@ enum class lcTransformType
Count
};
enum lcBackgroundType
{
LC_BACKGROUND_SOLID,
LC_BACKGROUND_GRADIENT,
LC_BACKGROUND_IMAGE
};
class lcModelProperties
{
public:
void LoadDefaults();
void SaveDefaults();
bool operator==(const lcModelProperties& Properties)
bool operator==(const lcModelProperties& Properties) const
{
if (mFileName != Properties.mFileName || mModelName != Properties.mModelName || mAuthor != Properties.mAuthor ||
mDescription != Properties.mDescription || mComments != Properties.mComments)
return false;
if (mBackgroundType != Properties.mBackgroundType || mBackgroundSolidColor != Properties.mBackgroundSolidColor ||
mBackgroundGradientColor1 != Properties.mBackgroundGradientColor1 || mBackgroundGradientColor2 != Properties.mBackgroundGradientColor2 ||
mBackgroundImage != Properties.mBackgroundImage || mBackgroundImageTile != Properties.mBackgroundImageTile)
return false;
if (mAmbientColor != Properties.mAmbientColor)
return false;
@ -78,13 +64,6 @@ public:
QString mAuthor;
QString mComments;
lcBackgroundType mBackgroundType;
lcVector3 mBackgroundSolidColor;
lcVector3 mBackgroundGradientColor1;
lcVector3 mBackgroundGradientColor2;
QString mBackgroundImage;
bool mBackgroundImageTile;
lcVector3 mAmbientColor;
};
@ -97,24 +76,33 @@ struct lcModelHistoryEntry
class lcModel
{
public:
lcModel(const QString& FileName);
lcModel(const QString& FileName, Project* Project, bool Preview);
~lcModel();
lcModel(const lcModel&) = delete;
lcModel(lcModel&&) = delete;
lcModel& operator=(const lcModel&) = delete;
lcModel& operator=(lcModel&&) = delete;
Project* GetProject() const
{
return mProject;
}
bool IsModified() const
{
return mSavedHistory != mUndoHistory[0];
}
bool IsActive() const
{
return mActive;
}
bool GetPieceWorldMatrix(lcPiece* Piece, lcMatrix44& ParentWorldMatrix) const;
bool IncludesModel(const lcModel* Model) const;
void CreatePieceInfo(Project* Project);
void UpdatePieceInfo(std::vector<lcModel*>& UpdatedModels);
void UpdateMesh();
void UpdateAllViews() const;
PieceInfo* GetPieceInfo() const
{
@ -228,27 +216,31 @@ public:
if (mUndoHistory.empty())
SaveCheckpoint(QString());
mSavedHistory = mUndoHistory[0];
if (!mIsPreview)
mSavedHistory = mUndoHistory[0];
}
void SetMinifig(const lcMinifig& Minifig);
void SetPreviewPieceInfo(PieceInfo* Info, int ColorIndex);
void Cut();
void Copy();
void Paste();
void Paste(bool PasteToCurrentStep);
void DuplicateSelectedPieces();
void PaintSelectedPieces();
void GetScene(lcScene& Scene, lcCamera* ViewCamera, bool AllowHighlight, bool AllowFade) const;
void AddSubModelRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
void DrawBackground(lcGLWidget* Widget);
void GetScene(lcScene* Scene, lcCamera* ViewCamera, bool AllowHighlight, bool AllowFade) const;
void AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
QImage GetStepImage(bool Zoom, int Width, int Height, lcStep Step);
QImage GetPartsListImage(int MaxWidth, lcStep Step) const;
QImage GetPartsListImage(int MaxWidth, lcStep Step, quint32 BackgroundColor, QFont Font, QColor TextColor) const;
void SaveStepImages(const QString& BaseName, bool AddStepSuffix, bool Zoom, int Width, int Height, lcStep Start, lcStep End);
std::vector<std::pair<lcModel*, lcStep>> GetPageLayouts(std::vector<const lcModel*>& AddedModels);
void RayTest(lcObjectRayTest& ObjectRayTest) const;
void BoxTest(lcObjectBoxTest& ObjectBoxTest) const;
bool SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVector3& WorldEnd, float& MinDistance) const;
bool SubModelBoxTest(const lcVector4 Planes[6]) const;
void SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const;
void SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const;
bool HasPieces() const
{
@ -266,6 +258,7 @@ public:
lcObject* GetFocusObject() const;
bool GetSelectionCenter(lcVector3& Center) const;
bool GetPiecesBoundingBox(lcVector3& Min, lcVector3& Max) const;
std::vector<lcVector3> GetPiecesBoundingBoxPoints() const;
void GetPartsList(int DefaultColorIndex, bool ScanSubModels, bool AddSubModels, lcPartsList& PartsList) const;
void GetPartsListForStep(lcStep Step, int DefaultColorIndex, lcPartsList& PartsList) const;
void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector<lcModelPartsEntry>& ModelParts) const;
@ -288,7 +281,7 @@ public:
void UnhideSelectedPieces();
void UnhideAllPieces();
void FindPiece(bool FindFirst, bool SearchForward);
void FindReplacePiece(bool SearchForward, bool FindAll);
void UndoAction();
void RedoAction();
@ -344,11 +337,10 @@ public:
void SetCameraFOV(lcCamera* Camera, float FOV);
void SetCameraZNear(lcCamera* Camera, float ZNear);
void SetCameraZFar(lcCamera* Camera, float ZFar);
void SetCameraName(lcCamera* Camera, const char* Name);
void SetCameraName(lcCamera* Camera, const QString& Name);
void ShowPropertiesDialog();
void ShowSelectByNameDialog();
void ShowSelectByColorDialog();
void ShowArrayDialog();
void ShowMinifigDialog();
void UpdateInterface();
@ -363,20 +355,19 @@ protected:
void RemoveEmptyGroups();
bool RemoveSelectedObjects();
void UpdateBackgroundTexture();
void SelectGroup(lcGroup* TopGroup, bool Select);
void AddPiece(lcPiece* Piece);
void InsertPiece(lcPiece* Piece, int Index);
lcModelProperties mProperties;
Project* const mProject;
PieceInfo* mPieceInfo;
bool mIsPreview;
bool mActive;
lcStep mCurrentStep;
lcVector3 mMouseToolDistance;
lcTexture* mBackgroundTexture;
lcArray<lcPiece*> mPieces;
lcArray<lcCamera*> mCameras;
@ -390,4 +381,3 @@ protected:
Q_DECLARE_TR_FUNCTIONS(lcModel);
};

View file

@ -0,0 +1,34 @@
#include "lc_global.h"
#include "lc_pagesetupdialog.h"
#include "ui_lc_pagesetupdialog.h"
#include "lc_instructions.h"
lcPageSetupDialog::lcPageSetupDialog(QWidget* Parent, lcInstructionsPageSetup* PageSetup)
: QDialog(Parent), ui(new Ui::lcPageSetupDialog), mPageSetup(PageSetup)
{
ui->setupUi(this);
ui->WidthEdit->setText(QString::number(PageSetup->Width));
ui->HeightEdit->setText(QString::number(PageSetup->Height));
ui->LeftEdit->setText(QString::number(PageSetup->MarginLeft));
ui->RightEdit->setText(QString::number(PageSetup->MarginRight));
ui->TopEdit->setText(QString::number(PageSetup->MarginTop));
ui->BottomEdit->setText(QString::number(PageSetup->MarginBottom));
}
lcPageSetupDialog::~lcPageSetupDialog()
{
delete ui;
}
void lcPageSetupDialog::accept()
{
mPageSetup->Width = ui->WidthEdit->text().toFloat();
mPageSetup->Height = ui->HeightEdit->text().toFloat();
mPageSetup->MarginLeft = ui->LeftEdit->text().toFloat();
mPageSetup->MarginRight = ui->RightEdit->text().toFloat();
mPageSetup->MarginTop = ui->TopEdit->text().toFloat();
mPageSetup->MarginBottom = ui->BottomEdit->text().toFloat();
QDialog::accept();
}

View file

@ -0,0 +1,22 @@
#pragma once
namespace Ui
{
class lcPageSetupDialog;
}
class lcPageSetupDialog : public QDialog
{
Q_OBJECT
public:
lcPageSetupDialog(QWidget* Parent, lcInstructionsPageSetup* PageSetup);
~lcPageSetupDialog();
public slots:
void accept() override;
private:
Ui::lcPageSetupDialog *ui;
lcInstructionsPageSetup* mPageSetup;
};

View file

@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>lcPageSetupDialog</class>
<widget class="QDialog" name="lcPageSetupDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Page Setup</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Size</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="3">
<widget class="QLineEdit" name="HeightEdit"/>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="WidthEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Width:</string>
</property>
<property name="buddy">
<cstring>WidthEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Height:</string>
</property>
<property name="buddy">
<cstring>HeightEdit</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Preset:</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="3">
<widget class="QComboBox" name="comboBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Units:</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QComboBox" name="comboBox_2"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Margins</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Left:</string>
</property>
<property name="buddy">
<cstring>LeftEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="LeftEdit"/>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Right:</string>
</property>
<property name="buddy">
<cstring>RightEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="RightEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Top:</string>
</property>
<property name="buddy">
<cstring>TopEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="TopEdit"/>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Bottom:</string>
</property>
<property name="buddy">
<cstring>BottomEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLineEdit" name="BottomEdit"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>WidthEdit</tabstop>
<tabstop>HeightEdit</tabstop>
<tabstop>comboBox_2</tabstop>
<tabstop>comboBox</tabstop>
<tabstop>LeftEdit</tabstop>
<tabstop>RightEdit</tabstop>
<tabstop>TopEdit</tabstop>
<tabstop>BottomEdit</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>lcPageSetupDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>227</x>
<y>282</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>lcPageSetupDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>295</x>
<y>288</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -9,10 +9,6 @@ lcPartPaletteDialog::lcPartPaletteDialog(QWidget* Parent, std::vector<lcPartPale
{
ui->setupUi(this);
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
ui->ImportButton->hide();
#endif
for (const lcPartPalette& Palette : PartPalettes)
{
QListWidgetItem* Item = new QListWidgetItem(Palette.Name);
@ -128,7 +124,6 @@ void lcPartPaletteDialog::on_ImportButton_clicked()
Palette->Name = Dialog.GetSetDescription();
mImportedPalettes.push_back(Palette);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QByteArray Inventory = Dialog.GetSetInventory();
QJsonDocument Document = QJsonDocument::fromJson(Inventory);
QJsonObject Root = Document.object();
@ -144,7 +139,6 @@ void lcPartPaletteDialog::on_ImportButton_clicked()
Palette->Parts.push_back(PartID.toUpper().toStdString() + ".DAT");
}
#endif
QListWidgetItem* Item = new QListWidgetItem(Palette->Name);
Item->setData(Qt::UserRole, QVariant::fromValue<uintptr_t>(reinterpret_cast<uintptr_t>(Palette)));

View file

@ -8,10 +8,13 @@
#include "lc_model.h"
#include "project.h"
#include "pieceinf.h"
#include "view.h"
#include "camera.h"
#include "lc_scene.h"
#include "lc_view.h"
#include "lc_glextensions.h"
#include "lc_category.h"
Q_DECLARE_METATYPE(QList<int>)
Q_DECLARE_METATYPE(QList<int>)
void lcPartSelectionItemDelegate::paint(QPainter* Painter, const QStyleOptionViewItem& Option, const QModelIndex& Index) const
{
@ -63,6 +66,9 @@ lcPartSelectionListModel::lcPartSelectionListModel(QObject* Parent)
lcPartSelectionListModel::~lcPartSelectionListModel()
{
ClearRequests();
mView.reset();
mModel.reset();
}
void lcPartSelectionListModel::ClearRequests()
@ -383,67 +389,56 @@ void lcPartSelectionListModel::PartLoaded(PieceInfo* Info)
void lcPartSelectionListModel::DrawPreview(int InfoIndex)
{
View* ActiveView = gMainWindow->GetActiveView();
if (!ActiveView)
return;
const int Width = mIconSize * 2;
const int Height = mIconSize * 2;
ActiveView->MakeCurrent();
lcContext* Context = ActiveView->mContext;
int Width = mIconSize * 2;
int Height = mIconSize * 2;
if (mView && (mView->GetWidth() != Width || mView->GetHeight() != Height))
mView.reset();
if (mRenderFramebuffer.first.mWidth != Width || mRenderFramebuffer.first.mHeight != Height)
if (!mView)
{
Context->DestroyRenderFramebuffer(mRenderFramebuffer);
mRenderFramebuffer = Context->CreateRenderFramebuffer(Width, Height);
if (!mModel)
mModel = std::unique_ptr<lcModel>(new lcModel(QString(), nullptr, true));
mView = std::unique_ptr<lcView>(new lcView(lcViewType::PartsList, mModel.get()));
mView->SetOffscreenContext();
mView->MakeCurrent();
mView->SetSize(Width, Height);
if (!mView->BeginRenderToImage(Width, Height))
{
mView.reset();
return;
}
}
if (!mRenderFramebuffer.first.IsValid())
return;
mView->MakeCurrent();
mView->BindRenderFramebuffer();
float Aspect = (float)Width / (float)Height;
Context->SetViewport(0, 0, Width, Height);
const uint BackgroundColor = mListView->palette().color(QPalette::Base).rgba();
mView->SetBackgroundColorOverride(LC_RGBA(qRed(BackgroundColor), qGreen(BackgroundColor), qBlue(BackgroundColor), 0));
Context->SetDefaultState();
Context->BindFramebuffer(mRenderFramebuffer.first);
lcPiecesLibrary* Library = lcGetPiecesLibrary();
PieceInfo* Info = mParts[InfoIndex].first;
mModel->SetPreviewPieceInfo(Info, mColorIndex);
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
lcMatrix44 ProjectionMatrix, ViewMatrix;
const lcVector3 Center = (Info->GetBoundingBox().Min + Info->GetBoundingBox().Max) / 2.0f;
const lcVector3 Position = Center + lcVector3(100.0f, -100.0f, 75.0f);
Info->ZoomExtents(20.0f, Aspect, ProjectionMatrix, ViewMatrix);
mView->GetCamera()->SetViewpoint(Position, Center, lcVector3(0, 0, 1));
mView->GetCamera()->m_fovy = 20.0f;
mView->ZoomExtents();
Context->SetProjectionMatrix(ProjectionMatrix);
mView->OnDraw();
lcScene Scene;
Scene.SetAllowWireframe(false);
Scene.SetAllowLOD(false);
Scene.Begin(ViewMatrix);
mView->UnbindRenderFramebuffer();
Info->AddRenderMeshes(Scene, lcMatrix44Identity(), mColorIndex, lcRenderMeshState::Default, false);
QImage Image = mView->GetRenderFramebufferImage().convertToFormat(QImage::Format_ARGB32);
Scene.End();
mParts[InfoIndex].second = QPixmap::fromImage(Image).scaled(mIconSize, mIconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
Scene.Draw(Context);
lcGetPiecesLibrary()->ReleasePieceInfo(Info);
mParts[InfoIndex].second = QPixmap::fromImage(Context->GetRenderFramebufferImage(mRenderFramebuffer)).scaled(mIconSize, mIconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
Library->ReleasePieceInfo(Info);
Context->ClearFramebuffer();
Context->ClearResources();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
QVector<int> Roles;
Roles.append(Qt::DecorationRole);
emit dataChanged(index(InfoIndex, 0), index(InfoIndex, 0), Roles);
#else
emit dataChanged(index(InfoIndex, 0), index(InfoIndex, 0));
#endif
emit dataChanged(index(InfoIndex, 0), index(InfoIndex, 0), QVector<int>() << Qt::DecorationRole);
}
void lcPartSelectionListModel::SetShowDecoratedParts(bool Show)
@ -514,9 +509,7 @@ lcPartSelectionListView::lcPartSelectionListView(QWidget* Parent, lcPartSelectio
lcPartSelectionItemDelegate* ItemDelegate = new lcPartSelectionItemDelegate(this, mListModel);
setItemDelegate(ItemDelegate);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
connect(this, SIGNAL(customContextMenuRequested(QPoint)), SLOT(CustomContextMenuRequested(QPoint)));
#endif
SetIconSize(lcGetProfileInt(LC_PROFILE_PARTS_LIST_ICONS));
}
@ -572,9 +565,9 @@ void lcPartSelectionListView::SetCategory(lcPartCategoryType Type, int Index)
case lcPartCategoryType::Category:
mListModel->SetCategory(Index);
break;
case lcPartCategoryType::Count:
break;
}
case lcPartCategoryType::Count:
break;
}
setCurrentIndex(mListModel->index(0, 0));
}
@ -680,6 +673,26 @@ void lcPartSelectionListView::startDrag(Qt::DropActions SupportedActions)
Drag->exec(Qt::CopyAction);
}
void lcPartSelectionListView::mouseDoubleClickEvent(QMouseEvent* MouseEvent)
{
if (MouseEvent->button() == Qt::LeftButton )
PreviewSelection(currentIndex().row());
QListView::mouseDoubleClickEvent(MouseEvent);
}
void lcPartSelectionListView::PreviewSelection(int InfoIndex)
{
PieceInfo* Info = mListModel->GetPieceInfo(InfoIndex);
if (!Info)
return;
quint32 ColorCode = lcGetColorCode(mListModel->GetColorIndex());
gMainWindow->PreviewPiece(Info->mFileName, ColorCode, true);
}
lcPartSelectionWidget::lcPartSelectionWidget(QWidget* Parent)
: QWidget(Parent), mFilterAction(nullptr)
{
@ -704,10 +717,8 @@ lcPartSelectionWidget::lcPartSelectionWidget(QWidget* Parent)
mFilterWidget = new QLineEdit(PartsGroupWidget);
mFilterWidget->setPlaceholderText(tr("Search Parts"));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
mFilterAction = mFilterWidget->addAction(QIcon(":/resources/parts_search.png"), QLineEdit::TrailingPosition);
connect(mFilterAction, SIGNAL(triggered()), this, SLOT(FilterTriggered()));
#endif
SearchLayout->addWidget(mFilterWidget);
QToolButton* OptionsButton = new QToolButton();
@ -866,7 +877,7 @@ void lcPartSelectionWidget::OptionsMenuAboutToShow()
lcPartSelectionListModel* ListModel = mPartsWidget->GetListModel();
if (gSupportsFramebufferObjectARB || gSupportsFramebufferObjectEXT)
if (gSupportsFramebufferObject)
{
QActionGroup* IconGroup = new QActionGroup(Menu);
@ -957,7 +968,6 @@ void lcPartSelectionWidget::SetDefaultPart()
void lcPartSelectionWidget::LoadPartPalettes()
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QByteArray Buffer = lcGetProfileBuffer(LC_PROFILE_PART_PALETTES);
QJsonDocument Document = QJsonDocument::fromJson(Buffer);
@ -988,12 +998,10 @@ void lcPartSelectionWidget::LoadPartPalettes()
mPartPalettes.emplace_back(std::move(Palette));
}
#endif
}
void lcPartSelectionWidget::SavePartPalettes()
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QJsonObject RootObject;
RootObject["Version"] = 1;
@ -1013,7 +1021,6 @@ void lcPartSelectionWidget::SavePartPalettes()
QByteArray Buffer = QJsonDocument(RootObject).toJson();
lcSetProfileBuffer(LC_PROFILE_PART_PALETTES, Buffer);
#endif
}
void lcPartSelectionWidget::AddToPalette()

View file

@ -88,6 +88,11 @@ public:
return mShowPartNames;
}
int GetColorIndex() const
{
return mColorIndex;
}
bool IsColorLocked() const
{
return mColorLocked;
@ -131,7 +136,8 @@ protected:
bool mShowDecoratedParts;
bool mShowPartAliases;
QByteArray mFilter;
std::pair<lcFramebuffer, lcFramebuffer> mRenderFramebuffer;
std::unique_ptr<lcView> mView;
std::unique_ptr<lcModel> mModel;
};
class lcPartSelectionListView : public QListView
@ -182,6 +188,8 @@ public slots:
protected:
void SetIconSize(int Size);
void PreviewSelection(int InfoIndex);
void mouseDoubleClickEvent(QMouseEvent* MouseEvent) override;
lcPartSelectionListModel* mListModel;
lcPartSelectionWidget* mPartSelectionWidget;

175
common/lc_previewwidget.cpp Normal file
View file

@ -0,0 +1,175 @@
#include "lc_global.h"
#include "lc_previewwidget.h"
#include "pieceinf.h"
#include "piece.h"
#include "project.h"
#include "lc_model.h"
#include "lc_library.h"
#include "lc_viewwidget.h"
#include "lc_view.h"
lcPreviewDockWidget::lcPreviewDockWidget(QMainWindow* Parent)
: QMainWindow(Parent)
{
mPreview = new lcPreview();
mViewWidget = new lcViewWidget(nullptr, mPreview);
setCentralWidget(mViewWidget);
setMinimumSize(200, 200);
mLockAction = new QAction(QIcon(":/resources/action_preview_unlocked.png"),tr("Lock Preview"), this);
mLockAction->setCheckable(true);
mLockAction->setChecked(false);
mLockAction->setShortcut(tr("Ctrl+L"));
connect(mLockAction, SIGNAL(triggered()), this, SLOT(SetPreviewLock()));
SetPreviewLock();
mLabel = new QLabel();
mToolBar = addToolBar(tr("Toolbar"));
mToolBar->setObjectName("Toolbar");
mToolBar->setStatusTip(tr("Preview Toolbar"));
mToolBar->setMovable(false);
mToolBar->addAction(mLockAction);
mToolBar->addSeparator();
mToolBar->addWidget(mLabel);
if (mToolBar->isHidden())
mToolBar->show();
}
bool lcPreviewDockWidget::SetCurrentPiece(const QString& PartType, int ColorCode)
{
if (mLockAction->isChecked())
return true;
mLabel->setText(tr("Loading..."));
if (mPreview->SetCurrentPiece(PartType, ColorCode))
{
mLabel->setText(mPreview->GetDescription());
return true;
}
return false;
}
void lcPreviewDockWidget::UpdatePreview()
{
mPreview->UpdatePreview();
}
void lcPreviewDockWidget::ClearPreview()
{
if (mPreview->GetModel()->GetPieces().GetSize())
mPreview->ClearPreview();
mLabel->setText(QString());
}
void lcPreviewDockWidget::SetPreviewLock()
{
bool Locked = mLockAction->isChecked();
if (Locked && mPreview->GetModel()->GetPieces().IsEmpty())
{
mLockAction->setChecked(false);
return;
}
QIcon LockIcon(Locked ? ":/resources/action_preview_locked.png" : ":/resources/action_preview_unlocked.png");
QString State(Locked ? tr("Unlock") : tr("Lock"));
QString StatusTip(tr("%1 the preview display to %2 updates").arg(State).arg(Locked ? "enable" : "disable"));
mLockAction->setToolTip(tr("%1 Preview").arg(State));
mLockAction->setIcon(LockIcon);
mLockAction->setStatusTip(StatusTip);
}
lcPreview::lcPreview()
: lcView(lcViewType::Preview, nullptr), mLoader(new Project(true))
{
mLoader->SetActiveModel(0);
mModel = mLoader->GetActiveModel();
}
bool lcPreview::SetCurrentPiece(const QString& PartType, int ColorCode)
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
PieceInfo* Info = Library->FindPiece(PartType.toLatin1().constData(), nullptr, false, false);
if (Info)
{
for (lcPiece* ModelPiece : mModel->GetPieces())
{
if (Info == ModelPiece->mPieceInfo)
{
int ModelColorCode = ModelPiece->GetColorCode();
if (ModelColorCode == ColorCode)
return true;
}
}
mIsModel = Info->IsModel();
mDescription = Info->m_strDescription;
mModel->SelectAllPieces();
mModel->DeleteSelectedObjects();
Library->LoadPieceInfo(Info, false, true);
Library->WaitForLoadQueue();
mModel->SetPreviewPieceInfo(Info, lcGetColorIndex(ColorCode));
Library->ReleasePieceInfo(Info);
}
else
{
QString ModelPath = QString("%1/%2").arg(QDir::currentPath()).arg(PartType);
if (!mLoader->Load(ModelPath))
{
QMessageBox::warning(nullptr, QMessageBox::tr("Error"), QMessageBox::tr("Failed to load '%1'.").arg(ModelPath));
return false;
}
mLoader->SetActiveModel(0);
lcGetPiecesLibrary()->RemoveTemporaryPieces();
mModel = mLoader->GetActiveModel();
if (!mModel->GetProperties().mDescription.isEmpty())
mDescription = mModel->GetProperties().mDescription;
else
mDescription = PartType;
mIsModel = true;
}
ZoomExtents();
return true;
}
void lcPreview::ClearPreview()
{
mLoader = std::unique_ptr<Project>(new Project(true/*IsPreview*/));
mLoader->SetActiveModel(0);
mModel = mLoader->GetActiveModel();
lcGetPiecesLibrary()->UnloadUnusedParts();
Redraw();
}
void lcPreview::UpdatePreview()
{
QString PartType;
int ColorCode = -1;
for (lcPiece* ModelPiece : mModel->GetPieces())
{
if (ModelPiece->mPieceInfo)
{
PartType = ModelPiece->mPieceInfo->mFileName;
ColorCode = ModelPiece->GetColorCode();
break;
}
}
ClearPreview();
if (!PartType.isEmpty() && ColorCode > -1)
SetCurrentPiece(PartType, ColorCode);
}

53
common/lc_previewwidget.h Normal file
View file

@ -0,0 +1,53 @@
#pragma once
#include "lc_view.h"
class lcPreview;
class lcPreviewDockWidget : public QMainWindow
{
Q_OBJECT
public:
explicit lcPreviewDockWidget(QMainWindow* Parent = nullptr);
bool SetCurrentPiece(const QString& PartType, int ColorCode);
void ClearPreview();
void UpdatePreview();
protected slots:
void SetPreviewLock();
protected:
QAction* mLockAction;
QToolBar* mToolBar;
QLabel* mLabel;
lcPreview* mPreview;
lcViewWidget* mViewWidget;
};
class lcPreview : public lcView
{
public:
lcPreview();
QString GetDescription() const
{
return mDescription;
}
bool IsModel() const
{
return mIsModel;
}
void ClearPreview();
void UpdatePreview();
bool SetCurrentPiece(const QString& PartType, int ColorCode);
protected:
std::unique_ptr<Project> mLoader;
QString mDescription;
bool mIsModel = false;
};

View file

@ -4,6 +4,7 @@
#include "image.h"
#include "lc_model.h"
#include "project.h"
#include "lc_viewsphere.h"
lcProfileEntry::lcProfileEntry(const char* Section, const char* Key, int DefaultValue)
{
@ -58,27 +59,41 @@ static lcProfileEntry gProfileEntries[LC_NUM_PROFILE_KEYS] =
lcProfileEntry("Settings", "FixedAxes", false), // LC_PROFILE_FIXED_AXES
lcProfileEntry("Settings", "LineWidth", 1.0f), // LC_PROFILE_LINE_WIDTH
lcProfileEntry("Settings", "AllowLOD", true), // LC_PROFILE_ALLOW_LOD
lcProfileEntry("Settings", "LODDistance", 750.0f), // LC_PROFILE_LOD_DISTANCE
lcProfileEntry("Settings", "FadeSteps", false), // LC_PROFILE_FADE_STEPS
lcProfileEntry("Settings", "FadeStepsColor", LC_RGBA(128, 128, 128, 128)), // LC_PROFILE_FADE_STEPS_COLOR
lcProfileEntry("Settings", "HighlightNewParts", 0), // LC_PROFILE_HIGHLIGHT_NEW_PARTS
lcProfileEntry("Settings", "HighlightNewPartsColor", LC_RGBA(255, 242, 0, 192)), // LC_PROFILE_HIGHLIGHT_NEW_PARTS_COLOR
lcProfileEntry("Settings", "ShadingMode", static_cast<int>(lcShadingMode::DefaultLights)), // LC_PROFILE_SHADING_MODE
lcProfileEntry("Settings", "BackgroundGradient", false), // LC_PROFILE_BACKGROUND_GRADIENT
lcProfileEntry("Settings", "BackgroundColor", LC_RGB(49, 52, 55)), // LC_PROFILE_BACKGROUND_COLOR
lcProfileEntry("Settings", "GradientColorTop", LC_RGB(54, 72, 95)), // LC_PROFILE_GRADIENT_COLOR_TOP
lcProfileEntry("Settings", "GradientColorBottom", LC_RGB(49, 52, 55)), // LC_PROFILE_GRADIENT_COLOR_BOTTOM
lcProfileEntry("Settings", "DrawAxes", 0), // LC_PROFILE_DRAW_AXES
lcProfileEntry("Settings", "AxesColor", LC_RGBA(0, 0, 0, 255)), // LC_PROFILE_AXES_COLOR
lcProfileEntry("Settings", "TextColor", LC_RGBA(0, 0, 0, 255)), // LC_PROFILE_TEXT_COLOR
lcProfileEntry("Settings", "MarqueeBorderColor", LC_RGBA(64, 64, 255, 255)), // LC_PROFILE_MARQUEE_BORDER_COLOR
lcProfileEntry("Settings", "MarqueeFillColor", LC_RGBA(64, 64, 255, 64)), // LC_PROFILE_MARQUEE_FILL_COLOR
lcProfileEntry("Settings", "OverlayColor", LC_RGBA(0, 0, 0, 255)), // LC_PROFILE_OVERLAY_COLOR
lcProfileEntry("Settings", "ActiveViewColor", LC_RGBA(41, 128, 185, 255)), // LC_PROFILE_ACTIVE_VIEW_COLOR
lcProfileEntry("Settings", "InactiveViewColor", LC_RGBA(69, 69, 69, 255)), // LC_PROFILE_INACTIVE_VIEW_COLOR
lcProfileEntry("Settings", "DrawEdgeLines", 1), // LC_PROFILE_DRAW_EDGE_LINES
lcProfileEntry("Settings", "GridStuds", 1), // LC_PROFILE_GRID_STUDS
lcProfileEntry("Settings", "GridStudColor", LC_RGBA(64, 64, 64, 192)), // LC_PROFILE_GRID_STUD_COLOR
lcProfileEntry("Settings", "GridStudColor", LC_RGBA(24, 24, 24, 192)), // LC_PROFILE_GRID_STUD_COLOR
lcProfileEntry("Settings", "GridLines", 1), // LC_PROFILE_GRID_LINES
lcProfileEntry("Settings", "GridLineSpacing", 5), // LC_PROFILE_GRID_LINE_SPACING
lcProfileEntry("Settings", "GridLineColor", LC_RGBA(0, 0, 0, 255)), // LC_PROFILE_GRID_LINE_COLOR
lcProfileEntry("Settings", "GridLineColor", LC_RGBA(24, 24, 24, 255)), // LC_PROFILE_GRID_LINE_COLOR
lcProfileEntry("Settings", "GridOrigin", 0), // LC_PROFILE_GRID_ORIGIN
lcProfileEntry("Settings", "AASamples", 1), // LC_PROFILE_ANTIALIASING_SAMPLES
lcProfileEntry("Settings", "ViewSphereEnabled", 1), // LC_PROFILE_VIEW_SPHERE_ENABLED
lcProfileEntry("Settings", "ViewSphereLocation", (int)lcViewSphereLocation::TopRight), // LC_PROFILE_VIEW_SPHERE_LOCATION
lcProfileEntry("Settings", "ViewSphereSize", 100), // LC_PROFILE_VIEW_SPHERE_SIZE
lcProfileEntry("Settings", "ViewSphereColor", LC_RGBA(255, 255, 255, 255)), // LC_PROFILE_VIEW_SPHERE_COLOR
lcProfileEntry("Settings", "ViewSphereTextColor", LC_RGBA(0, 0, 0, 255)), // LC_PROFILE_VIEW_SPHERE_TEXT_COLOR
lcProfileEntry("Settings", "ViewSphereHighlightColor", LC_RGBA(255, 0, 0, 255)), // LC_PROFILE_VIEW_SPHERE_HIGHLIGHT_COLOR
lcProfileEntry("Settings", "ViewSphereColor", LC_RGBA(35, 38, 41, 255)), // LC_PROFILE_VIEW_SPHERE_COLOR
lcProfileEntry("Settings", "ViewSphereTextColor", LC_RGBA(224, 224, 224, 255)), // LC_PROFILE_VIEW_SPHERE_TEXT_COLOR
lcProfileEntry("Settings", "ViewSphereHighlightColor", LC_RGBA(41, 128, 185, 255)), // LC_PROFILE_VIEW_SPHERE_HIGHLIGHT_COLOR
lcProfileEntry("Settings", "Language", ""), // LC_PROFILE_LANGUAGE
lcProfileEntry("Settings", "ColorTheme", static_cast<int>(lcColorTheme::Dark)), // LC_PROFILE_COLOR_THEME
lcProfileEntry("Settings", "CheckUpdates", 1), // LC_PROFILE_CHECK_UPDATES
lcProfileEntry("Settings", "ProjectsPath", ""), // LC_PROFILE_PROJECTS_PATH
lcProfileEntry("Settings", "PartsLibrary", ""), // LC_PROFILE_PARTS_LIBRARY
@ -105,18 +120,10 @@ static lcProfileEntry gProfileEntries[LC_NUM_PROFILE_KEYS] =
lcProfileEntry("Settings", "PartsListDecorated", 1), // LC_PROFILE_PARTS_LIST_DECORATED
lcProfileEntry("Settings", "PartsListAliases", 1), // LC_PROFILE_PARTS_LIST_ALIASES
lcProfileEntry("Settings", "PartsListListMode", 0), // LC_PROFILE_PARTS_LIST_LISTMODE
lcProfileEntry("Settings", "StudLogo", 0), // LC_PROFILE_STUD_LOGO
lcProfileEntry("Settings", "StudStyle", 0), // LC_PROFILE_STUD_STYLE
lcProfileEntry("Defaults", "Author", ""), // LC_PROFILE_DEFAULT_AUTHOR_NAME
lcProfileEntry("Defaults", "FloorColor", LC_RGB(0, 191, 0)), // LC_PROFILE_DEFAULT_FLOOR_COLOR
lcProfileEntry("Defaults", "FloorTexture", ""), // LC_PROFILE_DEFAULT_FLOOR_TEXTURE
lcProfileEntry("Defaults", "AmbientColor", LC_RGB(75, 75, 75)), // LC_PROFILE_DEFAULT_AMBIENT_COLOR
lcProfileEntry("Defaults", "BackgroundType", LC_BACKGROUND_SOLID), // LC_PROFILE_DEFAULT_BACKGROUND_TYPE
lcProfileEntry("Defaults", "BackgroundColor", LC_RGB(255, 255, 255)), // LC_PROFILE_DEFAULT_BACKGROUND_COLOR
lcProfileEntry("Defaults", "GradientColor1", LC_RGB(0, 0, 191)), // LC_PROFILE_DEFAULT_GRADIENT_COLOR1
lcProfileEntry("Defaults", "GradientColor2", LC_RGB(255, 255, 255)), // LC_PROFILE_DEFAULT_GRADIENT_COLOR2
lcProfileEntry("Defaults", "BackgroundTexture", ""), // LC_PROFILE_DEFAULT_BACKGROUND_TEXTURE
lcProfileEntry("Defaults", "BackgroundTile", 0), // LC_PROFILE_DEFAULT_BACKGROUND_TILE
lcProfileEntry("HTML", "Options", LC_HTML_SINGLEPAGE), // LC_PROFILE_HTML_OPTIONS
lcProfileEntry("HTML", "ImageOptions", LC_IMAGE_TRANSPARENT), // LC_PROFILE_HTML_IMAGE_OPTIONS
@ -126,7 +133,20 @@ static lcProfileEntry gProfileEntries[LC_NUM_PROFILE_KEYS] =
lcProfileEntry("POVRay", "Path", "/usr/bin/povray"), // LC_PROFILE_POVRAY_PATH
lcProfileEntry("POVRay", "LGEOPath", ""), // LC_PROFILE_POVRAY_LGEO_PATH
lcProfileEntry("POVRay", "Width", 1280), // LC_PROFILE_POVRAY_WIDTH
lcProfileEntry("POVRay", "Height", 720) // LC_PROFILE_POVRAY_HEIGHT
lcProfileEntry("POVRay", "Height", 720), // LC_PROFILE_POVRAY_HEIGHT
lcProfileEntry("Settgins", "PreviewViewSphereEnabled", 0), // LC_PROFILE_PREVIEW_VIEW_SPHERE_ENABLED
lcProfileEntry("Settings", "PreviewViewSphereSize", 75), // LC_PROFILE_PREVIEW_VIEW_SPHERE_SIZE
lcProfileEntry("Settings", "PreviewViewSphereLocation", (int)lcViewSphereLocation::TopRight), // LC_PROFILE_PREVIEW_VIEW_SPHERE_LOCATION
lcProfileEntry("Settings", "DrawPreviewAxis", 0), // LC_PROFILE_PREVIEW_DRAW_AXES
lcProfileEntry("Settings", "StudCylinderColor", LC_RGBA(27, 42, 52, 255)), // LC_PROFILE_STUD_CYLINDER_COLOR
lcProfileEntry("Settings", "PartEdgeColor", LC_RGBA(0, 0, 0, 255)), // LC_PROFILE_PART_EDGE_COLOR
lcProfileEntry("Settings", "BlackEdgeColor", LC_RGBA(255, 255, 255, 255)), // LC_PROFILE_BLACK_EDGE_COLOR
lcProfileEntry("Settings", "DarkEdgeColor", LC_RGBA(27, 42, 52, 255)), // LC_PROFILE_DARK_EDGE_COLOR
lcProfileEntry("Settings", "PartEdgeContrast", 0.5f), // LC_PROFILE_PART_EDGE_CONTRAST
lcProfileEntry("Settings", "mPartColorValueLDIndex", 0.5f), // LC_PROFILE_PART_COLOR_VALUE_LD_INDEX
lcProfileEntry("Settings", "AutomateEdgeColor", 0) // LC_PROFILE_AUTOMATE_EDGE_COLOR
};
void lcRemoveProfileKey(LC_PROFILE_KEY Key)

View file

@ -6,18 +6,31 @@ enum LC_PROFILE_KEY
LC_PROFILE_FIXED_AXES,
LC_PROFILE_LINE_WIDTH,
LC_PROFILE_ALLOW_LOD,
LC_PROFILE_LOD_DISTANCE,
LC_PROFILE_FADE_STEPS,
LC_PROFILE_FADE_STEPS_COLOR,
LC_PROFILE_HIGHLIGHT_NEW_PARTS,
LC_PROFILE_HIGHLIGHT_NEW_PARTS_COLOR,
LC_PROFILE_SHADING_MODE,
LC_PROFILE_BACKGROUND_GRADIENT,
LC_PROFILE_BACKGROUND_COLOR,
LC_PROFILE_GRADIENT_COLOR_TOP,
LC_PROFILE_GRADIENT_COLOR_BOTTOM,
LC_PROFILE_DRAW_AXES,
LC_PROFILE_AXES_COLOR,
LC_PROFILE_TEXT_COLOR,
LC_PROFILE_MARQUEE_BORDER_COLOR,
LC_PROFILE_MARQUEE_FILL_COLOR,
LC_PROFILE_OVERLAY_COLOR,
LC_PROFILE_ACTIVE_VIEW_COLOR,
LC_PROFILE_INACTIVE_VIEW_COLOR,
LC_PROFILE_DRAW_EDGE_LINES,
LC_PROFILE_GRID_STUDS,
LC_PROFILE_GRID_STUD_COLOR,
LC_PROFILE_GRID_LINES,
LC_PROFILE_GRID_LINE_SPACING,
LC_PROFILE_GRID_LINE_COLOR,
LC_PROFILE_GRID_ORIGIN,
LC_PROFILE_ANTIALIASING_SAMPLES,
LC_PROFILE_VIEW_SPHERE_ENABLED,
LC_PROFILE_VIEW_SPHERE_LOCATION,
@ -27,6 +40,7 @@ enum LC_PROFILE_KEY
LC_PROFILE_VIEW_SPHERE_HIGHLIGHT_COLOR,
LC_PROFILE_LANGUAGE,
LC_PROFILE_COLOR_THEME,
LC_PROFILE_CHECK_UPDATES,
LC_PROFILE_PROJECTS_PATH,
LC_PROFILE_PARTS_LIBRARY,
@ -53,19 +67,11 @@ enum LC_PROFILE_KEY
LC_PROFILE_PARTS_LIST_DECORATED,
LC_PROFILE_PARTS_LIST_ALIASES,
LC_PROFILE_PARTS_LIST_LISTMODE,
LC_PROFILE_STUD_LOGO,
LC_PROFILE_STUD_STYLE,
// Defaults for new projects.
LC_PROFILE_DEFAULT_AUTHOR_NAME,
LC_PROFILE_DEFAULT_FLOOR_COLOR,
LC_PROFILE_DEFAULT_FLOOR_TEXTURE,
LC_PROFILE_DEFAULT_AMBIENT_COLOR,
LC_PROFILE_DEFAULT_BACKGROUND_TYPE,
LC_PROFILE_DEFAULT_BACKGROUND_COLOR,
LC_PROFILE_DEFAULT_GRADIENT_COLOR1,
LC_PROFILE_DEFAULT_GRADIENT_COLOR2,
LC_PROFILE_DEFAULT_BACKGROUND_TEXTURE,
LC_PROFILE_DEFAULT_BACKGROUND_TILE,
// Exporters.
LC_PROFILE_HTML_OPTIONS,
@ -77,6 +83,19 @@ enum LC_PROFILE_KEY
LC_PROFILE_POVRAY_WIDTH,
LC_PROFILE_POVRAY_HEIGHT,
LC_PROFILE_PREVIEW_VIEW_SPHERE_ENABLED,
LC_PROFILE_PREVIEW_VIEW_SPHERE_SIZE,
LC_PROFILE_PREVIEW_VIEW_SPHERE_LOCATION,
LC_PROFILE_PREVIEW_DRAW_AXES,
LC_PROFILE_STUD_CYLINDER_COLOR,
LC_PROFILE_PART_EDGE_COLOR,
LC_PROFILE_BLACK_EDGE_COLOR,
LC_PROFILE_DARK_EDGE_COLOR,
LC_PROFILE_PART_EDGE_CONTRAST,
LC_PROFILE_PART_COLOR_VALUE_LD_INDEX,
LC_PROFILE_AUTOMATE_EDGE_COLOR,
LC_NUM_PROFILE_KEYS
};
@ -129,4 +148,3 @@ void lcSetProfileFloat(LC_PROFILE_KEY Key, float Value);
void lcSetProfileString(LC_PROFILE_KEY Key, const QString& Value);
void lcSetProfileStringList(LC_PROFILE_KEY Key, const QStringList& Value);
void lcSetProfileBuffer(LC_PROFILE_KEY Key, const QByteArray& Buffer);

View file

@ -12,8 +12,9 @@ lcScene::lcScene()
{
mActiveSubmodelInstance = nullptr;
mDrawInterface = false;
mAllowWireframe = true;
mShadingMode = lcShadingMode::DefaultLights;
mAllowLOD = true;
mMeshLODDistance = 250.0f;
mHasFadedParts = false;
mPreTranslucentCallback = nullptr;
}
@ -69,7 +70,7 @@ void lcScene::AddMesh(lcMesh* Mesh, const lcMatrix44& WorldMatrix, int ColorInde
RenderMesh.Mesh = Mesh;
RenderMesh.ColorIndex = ColorIndex;
RenderMesh.State = State;
const float Distance = fabsf(lcMul31(WorldMatrix[3], mViewMatrix).z);
const float Distance = fabsf(lcMul31(WorldMatrix[3], mViewMatrix).z) - mMeshLODDistance;
RenderMesh.LodIndex = mAllowLOD ? RenderMesh.Mesh->GetLodIndex(Distance) : LC_MESH_LOD_HIGH;
const bool ForceTranslucent = (mTranslucentFade && State == lcRenderMeshState::Faded);
@ -206,10 +207,20 @@ void lcScene::DrawOpaqueMeshes(lcContext* Context, bool DrawLit, int PrimitiveTy
switch (RenderMesh.State)
{
case lcRenderMeshState::Default:
if (ColorIndex == gEdgeColor)
Context->SetEdgeColorIndex(RenderMesh.ColorIndex);
if (mShadingMode != lcShadingMode::Wireframe)
{
if (ColorIndex != gEdgeColor)
Context->SetColorIndex(ColorIndex);
else
Context->SetEdgeColorIndex(RenderMesh.ColorIndex);
}
else
{
if (ColorIndex == gEdgeColor)
ColorIndex = RenderMesh.ColorIndex;
Context->SetColorIndex(ColorIndex);
}
break;
case lcRenderMeshState::Selected:
@ -422,11 +433,11 @@ void lcScene::Draw(lcContext* Context) const
constexpr bool DrawConditional = false;
const lcPreferences& Preferences = lcGetPreferences();
lcShadingMode ShadingMode = Preferences.mShadingMode;
if (ShadingMode == lcShadingMode::Wireframe && !mAllowWireframe)
ShadingMode = lcShadingMode::Flat;
// lcShadingMode ShadingMode = Preferences.mShadingMode;
// if (ShadingMode == lcShadingMode::Wireframe && !mAllowWireframe)
// ShadingMode = lcShadingMode::Flat;
if (ShadingMode == lcShadingMode::Wireframe)
if (mShadingMode == lcShadingMode::Wireframe)
{
int PrimitiveTypes = LC_MESH_LINES;
@ -438,7 +449,7 @@ void lcScene::Draw(lcContext* Context) const
if (mPreTranslucentCallback)
mPreTranslucentCallback();
}
else if (ShadingMode == lcShadingMode::Flat)
else if (mShadingMode == lcShadingMode::Flat)
{
const bool DrawLines = Preferences.mDrawEdgeLines && Preferences.mLineWidth != 0.0f;

View file

@ -59,9 +59,9 @@ public:
return mDrawInterface;
}
void SetAllowWireframe(bool AllowWireframe)
void SetShadingMode(lcShadingMode ShadingMode)
{
mAllowWireframe = AllowWireframe;
mShadingMode = ShadingMode;
}
void SetAllowLOD(bool AllowLOD)
@ -69,6 +69,11 @@ public:
mAllowLOD = AllowLOD;
}
void SetLODDistance(float Distance)
{
mMeshLODDistance = Distance;
}
void SetPreTranslucentCallback(std::function<void()> Callback)
{
mPreTranslucentCallback = Callback;
@ -99,9 +104,10 @@ protected:
lcMatrix44 mViewMatrix;
lcMatrix44 mActiveSubmodelTransform;
lcPiece* mActiveSubmodelInstance;
lcShadingMode mShadingMode;
bool mDrawInterface;
bool mAllowWireframe;
bool mAllowLOD;
float mMeshLODDistance;
lcVector4 mFadeColor;
lcVector4 mHighlightColor;

View file

@ -1,43 +0,0 @@
#include "lc_global.h"
#include "lc_selectbycolordialog.h"
#include "lc_qcolorpicker.h"
lcSelectByColorDialog::lcSelectByColorDialog(QWidget* Parent, int ColorIndex)
: QDialog(Parent), mColorIndex(ColorIndex)
{
setWindowTitle(tr("Select By Color"));
QVBoxLayout* MainLayout = new QVBoxLayout(this);
QHBoxLayout* ColorLayout = new QHBoxLayout();
ColorLayout->setContentsMargins(0, 0, 0, 0);
QLabel* ColorLabel = new QLabel(tr("Color:"), this);
ColorLayout->addWidget(ColorLabel);
mColorPicker = new lcQColorPicker(this);
mColorPicker->setCurrentColor(mColorIndex);
ColorLayout->addWidget(mColorPicker);
MainLayout->addLayout(ColorLayout);
QDialogButtonBox* ButtonBox = new QDialogButtonBox(this);
ButtonBox->setOrientation(Qt::Horizontal);
ButtonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
MainLayout->addWidget(ButtonBox);
QObject::connect(ButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
QObject::connect(ButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
lcSelectByColorDialog::~lcSelectByColorDialog()
{
}
void lcSelectByColorDialog::accept()
{
mColorIndex = mColorPicker->currentColor();
QDialog::accept();
}

View file

@ -1,23 +0,0 @@
#pragma once
#include "lc_array.h"
class lcQColorPicker;
class lcSelectByColorDialog : public QDialog
{
public:
Q_OBJECT
public:
lcSelectByColorDialog(QWidget* Parent, int ColorIndex);
~lcSelectByColorDialog();
int mColorIndex;
public slots:
void accept() override;
protected:
lcQColorPicker* mColorPicker;
};

View file

@ -132,30 +132,49 @@ void lcMouseShortcuts::Reset()
{
memset(mShortcuts, 0, sizeof(mShortcuts));
mShortcuts[LC_TOOL_ROTATE_VIEW].Modifiers1 = Qt::AltModifier;
mShortcuts[LC_TOOL_ROTATE_VIEW].Button1 = Qt::LeftButton;
mShortcuts[LC_TOOL_ROTATE_VIEW].Modifiers2 = Qt::NoModifier;
mShortcuts[LC_TOOL_ROTATE_VIEW].Button2 = Qt::RightButton;
lcToolShortcut& RotateViewShortcut = mShortcuts[static_cast<int>(lcTool::RotateView)];
RotateViewShortcut.Modifiers1 = Qt::AltModifier;
RotateViewShortcut.Button1 = Qt::LeftButton;
RotateViewShortcut.Modifiers2 = Qt::NoModifier;
RotateViewShortcut.Button2 = Qt::RightButton;
#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
mShortcuts[LC_TOOL_PAN].Modifiers1 = Qt::AltModifier;
mShortcuts[LC_TOOL_PAN].Button1 = Qt::MiddleButton;
mShortcuts[LC_TOOL_PAN].Modifiers2 = Qt::ShiftModifier;
mShortcuts[LC_TOOL_PAN].Button2 = Qt::RightButton;
#else
mShortcuts[LC_TOOL_PAN].Modifiers1 = Qt::ShiftModifier;
mShortcuts[LC_TOOL_PAN].Button1 = Qt::RightButton;
#endif
lcToolShortcut& PanShortcut = mShortcuts[static_cast<int>(lcTool::Pan)];
PanShortcut.Modifiers1 = Qt::AltModifier;
PanShortcut.Button1 = Qt::MiddleButton;
PanShortcut.Modifiers2 = Qt::ShiftModifier;
PanShortcut.Button2 = Qt::RightButton;
mShortcuts[LC_TOOL_ZOOM].Modifiers1 = Qt::AltModifier;
mShortcuts[LC_TOOL_ZOOM].Button1 = Qt::RightButton;
lcToolShortcut& ZoomShortcut = mShortcuts[static_cast<int>(lcTool::Zoom)];
ZoomShortcut.Modifiers1 = Qt::AltModifier;
ZoomShortcut.Button1 = Qt::RightButton;
}
bool lcMouseShortcuts::Save(const QString& FileName)
{
QStringList Shortcuts;
if (!Save(Shortcuts))
return false;
QFile File(FileName);
if (!File.open(QIODevice::WriteOnly))
return false;
QTextStream Stream(&File);
for (const QString& Shortcut : Shortcuts)
Stream << Shortcut << QLatin1String("\n");
Stream.flush();
return true;
}
bool lcMouseShortcuts::Save(QStringList& Shortcuts)
{
Shortcuts.clear();
for (int ToolIdx = 0; ToolIdx < LC_NUM_TOOLS; ToolIdx++)
for (int ToolIdx = 0; ToolIdx < static_cast<int>(lcTool::Count); ToolIdx++)
{
int ButtonIndex1 = 0;
for (int Button1 = mShortcuts[ToolIdx].Button1; Button1; Button1 >>= 1)
@ -179,6 +198,22 @@ bool lcMouseShortcuts::Save(QStringList& Shortcuts)
return true;
}
bool lcMouseShortcuts::Load(const QString& FileName)
{
QFile File(FileName);
if (!File.open(QIODevice::ReadOnly))
return false;
QTextStream Stream(&File);
QStringList Lines;
while (!Stream.atEnd())
Lines += Stream.readLine();
return Load(Lines);
}
bool lcMouseShortcuts::Load(const QStringList& FullShortcuts)
{
memset(mShortcuts, 0, sizeof(mShortcuts));
@ -193,11 +228,11 @@ bool lcMouseShortcuts::Load(const QStringList& FullShortcuts)
QString Key = FullShortcut.left(Equals);
int ToolIdx;
for (ToolIdx = 0; ToolIdx < LC_NUM_TOOLS; ToolIdx++)
for (ToolIdx = 0; ToolIdx < static_cast<int>(lcTool::Count); ToolIdx++)
if (Key == gToolNames[ToolIdx])
break;
if (ToolIdx == LC_NUM_TOOLS)
if (ToolIdx == static_cast<int>(lcTool::Count))
continue;
QStringList Shortcuts = FullShortcut.mid(Equals + 1).split(',');
@ -233,9 +268,9 @@ bool lcMouseShortcuts::Load(const QStringList& FullShortcuts)
lcTool lcMouseShortcuts::GetTool(Qt::MouseButton Button, Qt::KeyboardModifiers Modifiers) const
{
for (int ToolIdx = 0; ToolIdx < LC_NUM_TOOLS; ToolIdx++)
for (int ToolIdx = 0; ToolIdx < static_cast<int>(lcTool::Count); ToolIdx++)
if ((mShortcuts[ToolIdx].Button1 == Button && mShortcuts[ToolIdx].Modifiers1 == Modifiers) || (mShortcuts[ToolIdx].Button2 == Button && mShortcuts[ToolIdx].Modifiers2 == Modifiers))
return (lcTool)ToolIdx;
return LC_NUM_TOOLS;
return lcTool::Count;
}

View file

@ -24,18 +24,22 @@ class lcMouseShortcuts
{
public:
void Reset();
bool Save(const QString& FileName);
bool Save(QStringList& Shortcuts);
bool Load(const QString& FileName);
bool Load(const QStringList& Shortcuts);
lcTool GetTool(Qt::MouseButton Button, Qt::KeyboardModifiers Modifiers) const;
struct
struct lcToolShortcut
{
Qt::KeyboardModifiers Modifiers1;
Qt::MouseButton Button1;
Qt::KeyboardModifiers Modifiers2;
Qt::MouseButton Button2;
}
mShortcuts[LC_NUM_TOOLS];
};
lcToolShortcut mShortcuts[static_cast<int>(lcTool::Count)];
};
extern lcMouseShortcuts gMouseShortcuts;

View file

@ -6,7 +6,7 @@
lcStringCache gStringCache;
lcStringCache::lcStringCache()
: mTexture(nullptr), mRefCount(0)
: mTexture(nullptr)
{
}
@ -15,27 +15,17 @@ lcStringCache::~lcStringCache()
delete mTexture;
}
void lcStringCache::AddRef(lcContext* Context)
void lcStringCache::Initialize(lcContext* Context)
{
Q_UNUSED(Context);
mRefCount++;
if (mRefCount == 1)
mTexture = new lcTexture();
mTexture = new lcTexture();
}
void lcStringCache::Release(lcContext* Context)
void lcStringCache::Reset()
{
mRefCount--;
if (mRefCount == 0)
{
Context->UnbindTexture2D(mTexture->mTexture); // todo: unbind from all contexts
delete mTexture;
mTexture = nullptr;
}
delete mTexture;
mTexture = nullptr;
}
void lcStringCache::CacheStrings(const QStringList& Strings)

View file

@ -11,8 +11,8 @@ public:
lcStringCache();
~lcStringCache();
void AddRef(lcContext* Context);
void Release(lcContext* Context);
void Initialize(lcContext* Context);
void Reset();
void CacheStrings(const QStringList& Strings);
void GetStringDimensions(int* cx, int* cy, const QString& String) const;
@ -20,7 +20,6 @@ public:
protected:
lcTexture* mTexture;
int mRefCount;
std::map<QString, lcStringCacheEntry> mStrings;
};

View file

@ -111,12 +111,17 @@ protected:
class lcSynthInfoActuator : public lcSynthInfoStraight
{
public:
explicit lcSynthInfoActuator(float Length);
explicit lcSynthInfoActuator(const char* BodyPart, const char* PistonPart, const char* AxlePart, float Length, float AxleOffset);
void GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const override;
protected:
void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const override;
const char* mBodyPart;
const char* mPistonPart;
const char* mAxlePart;
float mAxleOffset;
};
class lcSynthInfoUniversalJoint : public lcSynthInfo
@ -319,12 +324,22 @@ void lcSynthInit()
static const struct
{
char PartID[16];
char BodyPart[16];
char PistonPart[16];
char AxlePart[16];
float Length;
float AxleOffset;
}
Actuators[] =
{
{ "61927C01.dat", 270.00f }, // Technic Power Functions Linear Actuator (Extended)
{ "61927.dat", 170.00f } // Technic Power Functions Linear Actuator (Contracted)
{ "61927-F1.dat", "62271c01.dat", "62274c01.dat", "47157.dat", 170.00f, 0.0f }, // Technic Linear Actuator 8 x 2 x 2 (Contracted)
{ "61927-F2.dat", "62271c01.dat", "62274c01.dat", "47157.dat", 270.00f, 0.0f }, // Technic Linear Actuator 8 x 2 x 2 (Extended)
{ "61927C01.dat", "62271c01.dat", "62274c01.dat", "47157.dat", 270.00f, 0.0f }, // Moved to 61927-f2 (was Technic Power Functions Linear Actuator (Extended))
{ "61927.dat", "62271c01.dat", "62274c01.dat", "47157.dat", 170.00f, 0.0f }, // Moved to 61927-f1 (was Technic Power Functions Linear Actuator (Contracted))
{ "92693C01-F1.dat", "92693c01.dat", "92696.dat", "92695.dat", 120.00f, 30.0f }, // Technic Linear Actuator 4 x 1 x 1 (Contracted)
{ "92693C01-F2.dat", "92693c01.dat", "92696.dat", "92695.dat", 180.00f, 30.0f }, // Technic Linear Actuator 4 x 1 x 1 (Extended)
{ "92693C02.dat", "92693c01.dat", "92696.dat", "92695.dat", 120.00f, 30.0f }, // Moved to 92693c01-f1 (was Technic Linear Actuator Small (Contracted))
{ "92693C03.dat", "92693c01.dat", "92696.dat", "92695.dat", 180.00f, 30.0f }, // Moved to 92693c01-f2 (was Technic Linear Actuator Small (Extended))
};
for (const auto& ActuatorInfo: Actuators)
@ -332,7 +347,8 @@ void lcSynthInit()
PieceInfo* Info = Library->FindPiece(ActuatorInfo.PartID, nullptr, false, false);
if (Info)
Info->SetSynthInfo(new lcSynthInfoActuator(ActuatorInfo.Length));
Info->SetSynthInfo(new lcSynthInfoActuator(ActuatorInfo.BodyPart, ActuatorInfo.PistonPart,
ActuatorInfo.AxlePart, ActuatorInfo.Length, ActuatorInfo.AxleOffset));
}
static const struct
@ -345,9 +361,10 @@ void lcSynthInit()
}
UniversalJoints[] =
{
{ "61903.dat", 60.00f, 0.0f, "62520.dat", "62519.dat" }, // Technic Universal Joint 3L
{ "3712C01.dat", 60.00f, 30.0f, "3712.dat", "3326.dat" }, // Technic Universal Joint
{ "575C01.dat", 60.00f, 30.0f, "575.dat", "3326a.dat" } // Technic Universal Joint Type 1
{ "61903.dat", 60.00f, 0.0f, "62520.dat", "62519.dat" }, // Technic Universal Joint 3L (Complete)
{ "3712C01.dat", 60.00f, 30.0f, "3712.dat", "3326.dat" }, // Technic Universal Joint 4L with Bush Ends with Centre Type 2 (Complete)
{ "3712C03.dat", 60.00f, 30.0f, "3712.dat", "3326a.dat" }, // Technic Universal Joint 4L with Bush Ends with Centre Type 1 (Complete)
{ "575C01.dat", 60.00f, 30.0f, "575.dat", "3326a.dat" } // Technic Universal Joint Type 1 (Complete)
};
for (const auto& JointInfo: UniversalJoints)
@ -432,8 +449,8 @@ lcSynthInfoShockAbsorber::lcSynthInfoShockAbsorber(const char* SpringPart)
{
}
lcSynthInfoActuator::lcSynthInfoActuator(float Length)
: lcSynthInfoStraight(Length)
lcSynthInfoActuator::lcSynthInfoActuator(const char* BodyPart, const char* PistonPart, const char* AxlePart, float Length, float AxleOffset)
: lcSynthInfoStraight(Length), mBodyPart(BodyPart), mPistonPart(PistonPart), mAxlePart(AxlePart), mAxleOffset(AxleOffset)
{
}
@ -1327,13 +1344,15 @@ void lcSynthInfoActuator::AddParts(lcMemFile& File, lcLibraryMeshData&, const lc
lcVector3 Offset;
Offset = Sections[0].GetTranslation();
sprintf(Line, "1 25 %f %f %f 0 1 0 -1 0 0 0 0 1 47157.dat\n", Offset[0], Offset[1], Offset[2]);
sprintf(Line, "1 16 %f %f %f 1 0 0 0 1 0 0 0 1 %s\n", Offset[0], Offset[1], Offset[2], mBodyPart);
File.WriteBuffer(Line, strlen(Line));
sprintf(Line, "1 16 %f %f %f 1 0 0 0 1 0 0 0 1 62271c01.dat\n", Offset[0], Offset[1], Offset[2]);
Offset = lcMul(Sections[0], lcMatrix44Translation(lcVector3(0.0f, 0.0f, mAxleOffset))).GetTranslation();
sprintf(Line, "1 25 %f %f %f 0 1 0 -1 0 0 0 0 1 %s\n", Offset[0], Offset[1], Offset[2], mAxlePart);
File.WriteBuffer(Line, strlen(Line));
Offset = Sections[1].GetTranslation();
sprintf(Line, "1 72 %f %f %f 1 0 0 0 1 0 0 0 1 62274c01.dat\n", Offset[0], Offset[1], Offset[2]);
sprintf(Line, "1 72 %f %f %f 1 0 0 0 1 0 0 0 1 %s\n", Offset[0], Offset[1], Offset[2], mPistonPart);
File.WriteBuffer(Line, strlen(Line));
}

View file

@ -41,11 +41,7 @@ public:
{
mRefCount.ref();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) || QT_VERSION < QT_VERSION_CHECK(5, 0, 0) )
if (mRefCount == 1)
#else
if (mRefCount.load() == 1)
#endif
Load();
}

View file

@ -4,6 +4,8 @@
#include "piece.h"
#include "pieceinf.h"
#include "lc_mainwindow.h"
#include "lc_viewwidget.h"
#include "lc_previewwidget.h"
lcTimelineWidget::lcTimelineWidget(QWidget* Parent)
: QTreeWidget(Parent)
@ -188,7 +190,7 @@ void lcTimelineWidget::Update(bool Clear, bool UpdateItems)
{
PieceItem->setText(0, Piece->mPieceInfo->m_strDescription);
int ColorIndex = Piece->mColorIndex;
int ColorIndex = Piece->GetColorIndex();
if (!mIcons.contains(ColorIndex))
{
int Size = rowHeight(indexFromItem(PieceItem));
@ -209,7 +211,7 @@ void lcTimelineWidget::Update(bool Clear, bool UpdateItems)
QColor Color = palette().text().color();
if (Piece->IsHidden())
Color.setAlpha(128);
PieceItem->setTextColor(0, Color);
PieceItem->setForeground(0, Color);
}
PieceItem->setSelected(Piece->IsSelected());
@ -263,11 +265,11 @@ void lcTimelineWidget::UpdateCurrentStepItem()
QFont Font = CurrentStepItem->font(0);
Font.setBold(true);
CurrentStepItem->setFont(0, Font);
setCurrentItem(CurrentStepItem);
}
mCurrentStepItem = CurrentStepItem;
}
}
void lcTimelineWidget::UpdateSelection()
@ -507,6 +509,35 @@ void lcTimelineWidget::mousePressEvent(QMouseEvent* Event)
QTreeWidget::mousePressEvent(Event);
}
void lcTimelineWidget::mouseDoubleClickEvent(QMouseEvent* MouseEvent)
{
if (MouseEvent->button() == Qt::LeftButton)
{
QTreeWidgetItem* CurrentItem = currentItem();
PreviewSelection(CurrentItem);
}
QTreeWidget::mouseDoubleClickEvent(MouseEvent);
}
void lcTimelineWidget::PreviewSelection(QTreeWidgetItem* CurrentItem)
{
if (!CurrentItem)
return;
lcPiece* Piece = (lcPiece*)CurrentItem->data(0, Qt::UserRole).value<uintptr_t>();
if (!Piece)
return;
PieceInfo* Info = Piece->mPieceInfo;
if (!Info)
return;
gMainWindow->PreviewPiece(Info->mFileName, Piece->GetColorCode(), false);
}
void lcTimelineWidget::UpdateModel()
{
QList<QPair<lcPiece*, lcStep>> PieceSteps;

View file

@ -21,10 +21,12 @@ public slots:
void CurrentItemChanged(QTreeWidgetItem* Current, QTreeWidgetItem* Previous);
void ItemSelectionChanged();
void CustomMenuRequested(QPoint Pos);
void PreviewSelection(QTreeWidgetItem* Current);
protected:
void dropEvent(QDropEvent* DropEvent) override;
void mousePressEvent(QMouseEvent* MouseEvent) override;
void mouseDoubleClickEvent(QMouseEvent* MouseEvent) override;
void UpdateModel();
void UpdateCurrentStepItem();
@ -33,4 +35,3 @@ protected:
QTreeWidgetItem* mCurrentStepItem;
bool mIgnoreUpdates;
};

File diff suppressed because it is too large Load diff

351
common/lc_view.h Normal file
View file

@ -0,0 +1,351 @@
#pragma once
#include "lc_context.h"
#include "lc_math.h"
#include "lc_commands.h"
enum class lcDragState
{
None,
Piece,
Color
};
enum class lcCursor
{
First,
Hidden = First,
Default,
Brick,
Light,
Spotlight,
Camera,
Select,
SelectAdd,
SelectRemove,
Move,
Rotate,
RotateX,
RotateY,
Delete,
Paint,
ColorPicker,
Zoom,
ZoomRegion,
Pan,
Roll,
RotateView,
Count
};
enum class lcTrackButton
{
None,
Left,
Middle,
Right
};
enum class lcTrackTool
{
None,
Insert,
PointLight,
SpotLight,
Camera,
Select,
MoveX,
MoveY,
MoveZ,
MoveXY,
MoveXZ,
MoveYZ,
MoveXYZ,
RotateX,
RotateY,
RotateZ,
RotateXY,
RotateXYZ,
ScalePlus,
ScaleMinus,
Eraser,
Paint,
ColorPicker,
Zoom,
Pan,
OrbitX,
OrbitY,
OrbitXY,
Roll,
ZoomRegion,
Count
};
enum class lcViewType
{
View,
Preview,
Minifig,
PartsList,
Count
};
struct lcFindReplaceParams
{
PieceInfo* FindInfo = nullptr;
QString FindString;
int FindColorIndex = 0;
PieceInfo* ReplacePieceInfo = nullptr;
int ReplaceColorIndex = 0;
};
class lcView : public QObject
{
Q_OBJECT
public:
lcView(lcViewType ViewType, lcModel* Model);
~lcView();
lcView(const lcView&) = delete;
lcView& operator=(const lcView&) = delete;
static lcFindReplaceParams& GetFindReplaceParams()
{
return mFindReplaceParams;
}
void Clear()
{
mModel = nullptr;
mActiveSubmodelInstance = nullptr;
}
lcModel* GetModel() const
{
return mModel;
}
lcViewType GetViewType() const
{
return mViewType;
}
lcCamera* GetCamera() const
{
return mCamera;
}
bool IsLastFocused() const
{
return mLastFocusedView == this;
}
bool IsTracking() const
{
return mTrackButton != lcTrackButton::None;
}
int GetWidth() const
{
return mWidth;
}
int GetHeight() const
{
return mHeight;
}
void SetSize(int Width, int Height)
{
mWidth = Width;
mHeight = Height;
}
lcViewWidget* GetWidget() const
{
return mWidget;
}
void SetWidget(lcViewWidget* Widget)
{
mWidget = Widget;
}
int GetMouseX() const
{
return mMouseX;
}
int GetMouseY() const
{
return mMouseY;
}
void SetBackgroundColorOverride(quint32 BackgroundColor)
{
mOverrideBackgroundColor = true;
mBackgroundColor = BackgroundColor;
}
static void UpdateProjectViews(const Project* Project);
static void UpdateAllViews();
static void CreateResources(lcContext* Context);
static void DestroyResources(lcContext* Context);
void MakeCurrent();
void Redraw();
void SetOffscreenContext();
void SetFocus(bool Focus);
void SetMousePosition(int MouseX, int MouseY);
void SetMouseModifiers(Qt::KeyboardModifiers MouseModifiers);
lcModel* GetActiveModel() const;
void SetTopSubmodelActive();
void SetSelectedSubmodelActive();
void OnDraw();
void OnLeftButtonDown();
void OnLeftButtonUp();
void OnLeftButtonDoubleClick();
void OnMiddleButtonDown();
void OnMiddleButtonUp();
void OnRightButtonDown();
void OnRightButtonUp();
void OnBackButtonDown();
void OnBackButtonUp();
void OnForwardButtonDown();
void OnForwardButtonUp();
void OnMouseMove();
void OnMouseWheel(float Direction);
void BeginDrag(lcDragState DragState);
void EndDrag(bool Accept);
void UpdateCursor();
void StartOrbitTracking();
void CancelTrackingOrClearSelection();
void SetViewpoint(lcViewpoint Viewpoint);
void SetViewpoint(const lcVector3& Position);
void SetViewpoint(const lcVector3& Position, const lcVector3& Target, const lcVector3& Up);
void SetCameraAngles(float Latitude, float Longitude);
void SetDefaultCamera();
void SetCamera(lcCamera* Camera, bool ForceCopy);
void SetCamera(const QString& CameraName);
void SetCameraIndex(int Index);
void SetProjection(bool Ortho);
void LookAt();
void MoveCamera(const lcVector3& Direction);
void Zoom(float Amount);
void ZoomExtents();
void RemoveCamera();
void ShowContextMenu() const;
bool CloseFindReplaceDialog();
void ShowFindReplaceWidget(bool Replace);
lcVector3 GetMoveDirection(const lcVector3& Direction) const;
lcMatrix44 GetPieceInsertPosition(bool IgnoreSelected, PieceInfo* Info) const;
lcVector3 GetCameraLightInsertPosition() const;
void GetRayUnderPointer(lcVector3& Start, lcVector3& End) const;
lcObjectSection FindObjectUnderPointer(bool PiecesOnly, bool IgnoreSelected) const;
lcArray<lcObject*> FindObjectsInBox(float x1, float y1, float x2, float y2) const;
bool BeginRenderToImage(int Width, int Height);
void EndRenderToImage();
QImage GetRenderImage() const;
void BindRenderFramebuffer();
void UnbindRenderFramebuffer();
QImage GetRenderFramebufferImage() const;
std::vector<QImage> GetStepImages(lcStep Start, lcStep End);
void SaveStepImages(const QString& BaseName, bool AddStepSuffix, lcStep Start, lcStep End, std::function<void(const QString&)> ProgressCallback);
lcContext* mContext = nullptr;
signals:
void FocusReceived();
void CameraChanged();
protected:
static void CreateSelectMoveOverlayMesh(lcContext* Context);
void DrawBackground() const;
void DrawViewport() const;
void DrawAxes() const;
void DrawSelectMoveOverlay();
void DrawRotateOverlay();
void DrawSelectZoomRegionOverlay();
void DrawRotateViewOverlay();
void DrawGrid();
lcVector3 ProjectPoint(const lcVector3& Point) const;
lcVector3 UnprojectPoint(const lcVector3& Point) const;
void UnprojectPoints(lcVector3* Points, int NumPoints) const;
lcMatrix44 GetProjectionMatrix() const;
lcMatrix44 GetTileProjectionMatrix(int CurrentRow, int CurrentColumn, int CurrentTileWidth, int CurrentTileHeight) const;
lcCursor GetCursor() const;
void SetCursor(lcCursor Cursor);
lcTool GetCurrentTool() const;
void UpdateTrackTool();
bool IsTrackToolAllowed(lcTrackTool TrackTool, quint32 AllowedTransforms) const;
lcTrackTool GetOverrideTrackTool(Qt::MouseButton Button) const;
float GetOverlayScale() const;
void StartTracking(lcTrackButton TrackButton);
void StopTracking(bool Accept);
void OnButtonDown(lcTrackButton TrackButton);
lcViewWidget* mWidget = nullptr;
int mWidth = 1;
int mHeight = 1;
bool mDeleteContext = true;
lcViewType mViewType;
int mMouseX = 0;
int mMouseY = 0;
int mMouseDownX = 0;
int mMouseDownY = 0;
Qt::KeyboardModifiers mMouseModifiers = Qt::NoModifier;
bool mTrackUpdated = false;
bool mToolClicked = false;
lcTrackTool mTrackTool = lcTrackTool::None;
lcTrackButton mTrackButton = lcTrackButton::None;
lcCursor mCursor = lcCursor::Default;
lcDragState mDragState;
bool mTrackToolFromOverlay;
lcVector3 mMouseDownPosition;
PieceInfo* mMouseDownPiece;
QImage mRenderImage;
std::unique_ptr<QOpenGLFramebufferObject> mRenderFramebuffer;
bool mOverrideBackgroundColor = false;
quint32 mBackgroundColor = 0;
std::unique_ptr<lcScene> mScene;
std::unique_ptr<lcViewSphere> mViewSphere;
lcModel* mModel = nullptr;
lcPiece* mActiveSubmodelInstance = nullptr;
lcMatrix44 mActiveSubmodelTransform;
lcCamera* mCamera = nullptr;
lcVertexBuffer mGridBuffer;
int mGridSettings[7];
static lcFindReplaceWidget* mFindWidget;
static lcFindReplaceParams mFindReplaceParams;
static lcView* mLastFocusedView;
static std::vector<lcView*> mViews;
static lcVertexBuffer mRotateMoveVertexBuffer;
static lcIndexBuffer mRotateMoveIndexBuffer;
};

View file

@ -1,6 +1,7 @@
#include "lc_global.h"
#include "lc_viewsphere.h"
#include "view.h"
#include "lc_view.h"
#include "camera.h"
#include "lc_context.h"
#include "lc_stringcache.h"
#include "lc_application.h"
@ -14,15 +15,40 @@ const float lcViewSphere::mRadius = 1.0f;
const float lcViewSphere::mHighlightRadius = 0.35f;
const int lcViewSphere::mSubdivisions = 7;
lcViewSphere::lcViewSphere(View* View)
lcViewSphere::lcViewSphere(lcView* View)
: mView(View)
{
mMouseDown = false;
UpdateSettings();
}
void lcViewSphere::UpdateSettings()
{
const lcPreferences& Preferences = lcGetPreferences();
switch (mView->GetViewType())
{
case lcViewType::View:
mSize = Preferences.mViewSphereSize;
mEnabled = Preferences.mViewSphereEnabled;
mLocation = Preferences.mViewSphereLocation;
break;
case lcViewType::Preview:
mSize = Preferences.mPreviewViewSphereSize;
mEnabled = Preferences.mPreviewViewSphereEnabled;
mLocation = Preferences.mPreviewViewSphereLocation;
break;
case lcViewType::Minifig:
case lcViewType::PartsList:
case lcViewType::Count:
break;
}
}
lcMatrix44 lcViewSphere::GetViewMatrix() const
{
lcMatrix44 ViewMatrix = mView->mCamera->mWorldView;
lcMatrix44 ViewMatrix = mView->GetCamera()->mWorldView;
ViewMatrix.SetTranslation(lcVector3(0, 0, 0));
return ViewMatrix;
}
@ -151,23 +177,21 @@ void lcViewSphere::DestroyResources(lcContext* Context)
void lcViewSphere::Draw()
{
const lcPreferences& Preferences = lcGetPreferences();
int ViewportSize = Preferences.mViewSphereSize;
UpdateSettings();
if (ViewportSize == 0 || !Preferences.mViewSphereEnabled)
if (!mSize || !mEnabled)
return;
lcContext* Context = mView->mContext;
int Width = mView->mWidth;
int Height = mView->mHeight;
lcViewSphereLocation Location = Preferences.mViewSphereLocation;
int Left = (Location == lcViewSphereLocation::BottomLeft || Location == lcViewSphereLocation::TopLeft) ? 0 : Width - ViewportSize;
int Bottom = (Location == lcViewSphereLocation::BottomLeft || Location == lcViewSphereLocation::BottomRight) ? 0 : Height - ViewportSize;
const int Width = mView->GetWidth();
const int Height = mView->GetHeight();
const int ViewportSize = mSize;
const int Left = (mLocation == lcViewSphereLocation::BottomLeft || mLocation == lcViewSphereLocation::TopLeft) ? 0 : Width - ViewportSize;
const int Bottom = (mLocation == lcViewSphereLocation::BottomLeft || mLocation == lcViewSphereLocation::BottomRight) ? 0 : Height - ViewportSize;
Context->SetViewport(Left, Bottom, ViewportSize, ViewportSize);
glDepthFunc(GL_ALWAYS);
glEnable(GL_CULL_FACE);
Context->SetDepthFunction(lcDepthFunction::Always);
Context->EnableCullFace(true);
Context->SetVertexBuffer(mVertexBuffer);
Context->SetVertexFormatPosition(3);
@ -205,6 +229,7 @@ void lcViewSphere::Draw()
HighlightPosition = lcVector4(lcNormalize(lcVector3(HighlightPosition)), mHighlightRadius);
}
const lcPreferences& Preferences = lcGetPreferences();
const lcVector4 TextColor = lcVector4FromColor(Preferences.mViewSphereTextColor);
const lcVector4 BackgroundColor = lcVector4FromColor(Preferences.mViewSphereColor);
const lcVector4 HighlightColor = lcVector4FromColor(Preferences.mViewSphereHighlightColor);
@ -212,16 +237,15 @@ void lcViewSphere::Draw()
Context->SetHighlightParams(HighlightPosition, TextColor, BackgroundColor, HighlightColor);
Context->DrawIndexedPrimitives(GL_TRIANGLES, mSubdivisions * mSubdivisions * 6 * 6, GL_UNSIGNED_SHORT, 0);
glDisable(GL_CULL_FACE);
glDepthFunc(GL_LEQUAL);
Context->EnableCullFace(false);
Context->SetDepthFunction(lcDepthFunction::LessEqual);
Context->SetViewport(0, 0, Width, Height);
}
bool lcViewSphere::OnLeftButtonDown()
{
const lcPreferences& Preferences = lcGetPreferences();
if (Preferences.mViewSphereSize == 0 || !Preferences.mViewSphereEnabled)
if (!mSize || !mEnabled)
return false;
mIntersectionFlags = GetIntersectionFlags(mIntersection);
@ -229,8 +253,8 @@ bool lcViewSphere::OnLeftButtonDown()
if (!mIntersectionFlags.any())
return false;
mMouseDownX = mView->mInputState.x;
mMouseDownY = mView->mInputState.y;
mMouseDownX = mView->GetMouseX();
mMouseDownY = mView->GetMouseY();
mMouseDown = true;
return true;
@ -238,8 +262,7 @@ bool lcViewSphere::OnLeftButtonDown()
bool lcViewSphere::OnLeftButtonUp()
{
const lcPreferences& Preferences = lcGetPreferences();
if (Preferences.mViewSphereSize == 0 || !Preferences.mViewSphereEnabled)
if (!mSize || !mEnabled)
return false;
if (!mMouseDown)
@ -267,8 +290,7 @@ bool lcViewSphere::OnLeftButtonUp()
bool lcViewSphere::OnMouseMove()
{
const lcPreferences& Preferences = lcGetPreferences();
if (Preferences.mViewSphereSize == 0 || !Preferences.mViewSphereEnabled)
if (!mSize || !mEnabled)
return false;
if (IsDragging())
@ -294,21 +316,20 @@ bool lcViewSphere::OnMouseMove()
bool lcViewSphere::IsDragging() const
{
return mMouseDown && (qAbs(mMouseDownX - mView->mInputState.x) > 3 || qAbs(mMouseDownY - mView->mInputState.y) > 3);
int InputStateX = mView->GetMouseX();
int InputStateY = mView->GetMouseY();
return mMouseDown && (qAbs(mMouseDownX - InputStateX) > 3 || qAbs(mMouseDownY - InputStateY) > 3);
}
std::bitset<6> lcViewSphere::GetIntersectionFlags(lcVector3& Intersection) const
{
const lcPreferences& Preferences = lcGetPreferences();
lcViewSphereLocation Location = Preferences.mViewSphereLocation;
int Width = mView->mWidth;
int Height = mView->mHeight;
int ViewportSize = Preferences.mViewSphereSize;
int Left = (Location == lcViewSphereLocation::BottomLeft || Location == lcViewSphereLocation::TopLeft) ? 0 : Width - ViewportSize;
int Bottom = (Location == lcViewSphereLocation::BottomLeft || Location == lcViewSphereLocation::BottomRight) ? 0 : Height - ViewportSize;
int x = mView->mInputState.x - Left;
int y = mView->mInputState.y - Bottom;
const int Width = mView->GetWidth();
const int Height = mView->GetHeight();
const int ViewportSize = mSize;
const int Left = (mLocation == lcViewSphereLocation::BottomLeft || mLocation == lcViewSphereLocation::TopLeft) ? 0 : Width - ViewportSize;
const int Bottom = (mLocation == lcViewSphereLocation::BottomLeft || mLocation == lcViewSphereLocation::BottomRight) ? 0 : Height - ViewportSize;
const int x = mView->GetMouseX() - Left;
const int y = mView->GetMouseY() - Bottom;
std::bitset<6> IntersectionFlags;
if (x < 0 || x > Width || y < 0 || y > Height)

View file

@ -4,12 +4,18 @@
#include "lc_context.h"
#include <bitset>
class View;
enum class lcViewSphereLocation
{
TopLeft,
TopRight,
BottomLeft,
BottomRight
};
class lcViewSphere
{
public:
lcViewSphere(View* View);
lcViewSphere(lcView* View);
void Draw();
bool OnMouseMove();
@ -21,16 +27,23 @@ public:
static void DestroyResources(lcContext* Context);
protected:
void UpdateSettings();
lcMatrix44 GetViewMatrix() const;
lcMatrix44 GetProjectionMatrix() const;
std::bitset<6> GetIntersectionFlags(lcVector3& Intersection) const;
View* mView;
lcView* const mView = nullptr;
int mSize = 1;
bool mEnabled = false;
lcViewSphereLocation mLocation = lcViewSphereLocation::TopRight;
int mMouseDownX = 0;
int mMouseDownY = 0;
bool mMouseDown = false;
lcVector3 mIntersection;
std::bitset<6> mIntersectionFlags;
int mMouseDownX;
int mMouseDownY;
bool mMouseDown;
static lcTexture* mTexture;
static lcVertexBuffer mVertexBuffer;

312
common/lc_viewwidget.cpp Normal file
View file

@ -0,0 +1,312 @@
#include "lc_global.h"
#include "lc_viewwidget.h"
#include "lc_glextensions.h"
#include "project.h"
#include "lc_library.h"
#include "lc_application.h"
#include "lc_mainwindow.h"
#include "lc_context.h"
#include "lc_view.h"
#include "lc_texture.h"
#include "lc_mesh.h"
#include "lc_profile.h"
#include "lc_previewwidget.h"
static QList<lcViewWidget*> gWidgetList;
lcViewWidget::lcViewWidget(QWidget* Parent, lcView* View)
: QOpenGLWidget(Parent)
{
mWheelAccumulator = 0;
mView = View;
mView->SetWidget(this);
gWidgetList.append(this);
setMouseTracking(true);
if (View->GetViewType() == lcViewType::View)
{
setFocusPolicy(Qt::StrongFocus);
setAcceptDrops(true);
}
}
lcViewWidget::~lcViewWidget()
{
gWidgetList.removeOne(this);
delete mView;
}
QSize lcViewWidget::sizeHint() const
{
return mPreferredSize.isEmpty() ? QOpenGLWidget::sizeHint() : mPreferredSize;
}
void lcViewWidget::SetView(lcView* View)
{
if (View)
{
if (context())
{
makeCurrent();
View->mContext->SetGLContext(context(), this);
}
View->SetWidget(this);
const float Scale = GetDeviceScale();
View->SetSize(width() * Scale, height() * Scale);
if (hasFocus())
View->SetFocus(true);
}
delete mView;
mView = View;
}
void lcViewWidget::initializeGL()
{
mView->mContext->SetGLContext(context(), this);
}
void lcViewWidget::resizeGL(int Width, int Height)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
const float Scale = devicePixelRatioF();
#else
const int Scale = devicePixelRatio();
#endif
mView->SetSize(Width * Scale, Height * Scale);
}
void lcViewWidget::paintGL()
{
mView->OnDraw();
}
void lcViewWidget::focusInEvent(QFocusEvent* FocusEvent)
{
if (mView)
mView->SetFocus(true);
QOpenGLWidget::focusInEvent(FocusEvent);
}
void lcViewWidget::focusOutEvent(QFocusEvent* FocusEvent)
{
if (mView)
mView->SetFocus(false);
QOpenGLWidget::focusOutEvent(FocusEvent);
}
void lcViewWidget::keyPressEvent(QKeyEvent* KeyEvent)
{
if (KeyEvent->key() == Qt::Key_Control || KeyEvent->key() == Qt::Key_Shift)
{
mView->SetMouseModifiers(KeyEvent->modifiers());
mView->UpdateCursor();
}
QOpenGLWidget::keyPressEvent(KeyEvent);
}
void lcViewWidget::keyReleaseEvent(QKeyEvent* KeyEvent)
{
if (KeyEvent->key() == Qt::Key_Control || KeyEvent->key() == Qt::Key_Shift)
{
mView->SetMouseModifiers(KeyEvent->modifiers());
mView->UpdateCursor();
}
QOpenGLWidget::keyReleaseEvent(KeyEvent);
}
void lcViewWidget::mousePressEvent(QMouseEvent* MouseEvent)
{
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(MouseEvent->x() * DeviceScale, mView->GetHeight() - MouseEvent->y() * DeviceScale - 1);
mView->SetMouseModifiers(MouseEvent->modifiers());
switch (MouseEvent->button())
{
case Qt::LeftButton:
mView->OnLeftButtonDown();
break;
case Qt::MiddleButton:
mView->OnMiddleButtonDown();
break;
case Qt::RightButton:
mView->OnRightButtonDown();
break;
case Qt::BackButton:
mView->OnBackButtonDown();
break;
case Qt::ForwardButton:
mView->OnForwardButtonDown();
break;
default:
break;
}
}
void lcViewWidget::mouseReleaseEvent(QMouseEvent* MouseEvent)
{
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(MouseEvent->x() * DeviceScale, mView->GetHeight() - MouseEvent->y() * DeviceScale - 1);
mView->SetMouseModifiers(MouseEvent->modifiers());
switch (MouseEvent->button())
{
case Qt::LeftButton:
mView->OnLeftButtonUp();
break;
case Qt::MiddleButton:
mView->OnMiddleButtonUp();
break;
case Qt::RightButton:
mView->OnRightButtonUp();
break;
case Qt::BackButton:
mView->OnBackButtonUp();
break;
case Qt::ForwardButton:
mView->OnForwardButtonUp();
break;
default:
break;
}
}
void lcViewWidget::mouseDoubleClickEvent(QMouseEvent* MouseEvent)
{
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(MouseEvent->x() * DeviceScale, mView->GetHeight() - MouseEvent->y() * DeviceScale - 1);
mView->SetMouseModifiers(MouseEvent->modifiers());
switch (MouseEvent->button())
{
case Qt::LeftButton:
mView->OnLeftButtonDoubleClick();
break;
default:
break;
}
}
void lcViewWidget::mouseMoveEvent(QMouseEvent* MouseEvent)
{
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(MouseEvent->x() * DeviceScale, mView->GetHeight() - MouseEvent->y() * DeviceScale - 1);
mView->SetMouseModifiers(MouseEvent->modifiers());
mView->OnMouseMove();
}
void lcViewWidget::wheelEvent(QWheelEvent* WheelEvent)
{
if (WheelEvent->angleDelta().y() == 0)
{
WheelEvent->ignore();
return;
}
float DeviceScale = GetDeviceScale();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
mView->SetMousePosition(WheelEvent->position().x() * DeviceScale, mView->GetHeight() - WheelEvent->position().y() * DeviceScale - 1);
#else
mView->SetMousePosition(WheelEvent->x() * DeviceScale, mView->GetHeight() - WheelEvent->y() * DeviceScale - 1);
#endif
mView->SetMouseModifiers(WheelEvent->modifiers());
mWheelAccumulator += WheelEvent->angleDelta().y() / 8;
int numSteps = mWheelAccumulator / 15;
if (numSteps)
{
mView->OnMouseWheel(numSteps);
mWheelAccumulator -= numSteps * 15;
}
WheelEvent->accept();
}
void lcViewWidget::dragEnterEvent(QDragEnterEvent* DragEnterEvent)
{
const QMimeData* MimeData = DragEnterEvent->mimeData();
if (MimeData->hasFormat("application/vnd.leocad-part"))
{
DragEnterEvent->acceptProposedAction();
mView->BeginDrag(lcDragState::Piece);
return;
}
else if (MimeData->hasFormat("application/vnd.leocad-color"))
{
DragEnterEvent->acceptProposedAction();
mView->BeginDrag(lcDragState::Color);
return;
}
DragEnterEvent->ignore();
}
void lcViewWidget::dragLeaveEvent(QDragLeaveEvent* DragLeaveEvent)
{
mView->EndDrag(false);
DragLeaveEvent->accept();
}
void lcViewWidget::dragMoveEvent(QDragMoveEvent* DragMoveEvent)
{
const QMimeData* MimeData = DragMoveEvent->mimeData();
if (MimeData->hasFormat("application/vnd.leocad-part") || MimeData->hasFormat("application/vnd.leocad-color"))
{
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(DragMoveEvent->pos().x() * DeviceScale, mView->GetHeight() - DragMoveEvent->pos().y() * DeviceScale - 1);
mView->SetMouseModifiers(DragMoveEvent->keyboardModifiers());
mView->OnMouseMove();
DragMoveEvent->accept();
return;
}
QOpenGLWidget::dragMoveEvent(DragMoveEvent);
}
void lcViewWidget::dropEvent(QDropEvent* DropEvent)
{
const QMimeData* MimeData = DropEvent->mimeData();
if (MimeData->hasFormat("application/vnd.leocad-part") || MimeData->hasFormat("application/vnd.leocad-color"))
{
mView->EndDrag(true);
setFocus(Qt::MouseFocusReason);
DropEvent->accept();
return;
}
QOpenGLWidget::dropEvent(DropEvent);
}

View file

@ -1,35 +1,37 @@
#pragma once
#include <QGLWidget>
class lcGLWidget;
class lcQGLWidget : public QGLWidget
class lcViewWidget : public QOpenGLWidget
{
Q_OBJECT
public:
lcQGLWidget(QWidget* Parent, lcGLWidget* Owner, bool IsView);
~lcQGLWidget();
lcViewWidget(QWidget* Parent, lcView* View);
~lcViewWidget();
lcView* GetView() const
{
return mView;
}
void SetView(lcView* View);
QSize sizeHint() const override;
lcGLWidget *widget;
QSize preferredSize;
bool mIsView;
float deviceScale()
protected:
float GetDeviceScale() const
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
return windowHandle()->devicePixelRatio();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
return devicePixelRatioF();
#else
return 1.0f;
return devicePixelRatio();
#endif
}
QTimer mUpdateTimer;
protected:
void initializeGL() override;
void resizeGL(int Width, int Height) override;
void paintGL() override;
void focusInEvent(QFocusEvent* FocusEvent) override;
void focusOutEvent(QFocusEvent* FocusEvent) override;
void keyPressEvent(QKeyEvent* KeyEvent) override;
void keyReleaseEvent(QKeyEvent* KeyEvent) override;
void mousePressEvent(QMouseEvent* MouseEvent) override;
@ -42,6 +44,7 @@ protected:
void dragMoveEvent(QDragMoveEvent* DragMoveEvent) override;
void dropEvent(QDropEvent* DropEvent) override;
lcView* mView;
QSize mPreferredSize;
int mWheelAccumulator;
};

View file

@ -14,32 +14,25 @@
lcZipFile::lcZipFile()
{
mModified = false;
mFile = nullptr;
}
lcZipFile::~lcZipFile()
{
delete mFile;
}
bool lcZipFile::OpenRead(const QString& FileName)
{
lcDiskFile* File = new lcDiskFile(FileName);
mFile = File;
std::unique_ptr<lcDiskFile> File(new lcDiskFile(FileName));
if (!File->Open(QIODevice::ReadOnly) || !Open())
{
delete File;
mFile = nullptr;
if (!File->Open(QIODevice::ReadOnly))
return false;
}
return true;
return OpenRead(std::move(File));
}
bool lcZipFile::OpenRead(lcFile* File)
bool lcZipFile::OpenRead(std::unique_ptr<lcFile> File)
{
mFile = File;
mFile = std::move(File);
if (!Open())
{
@ -52,8 +45,12 @@ bool lcZipFile::OpenRead(lcFile* File)
bool lcZipFile::OpenWrite(const QString& FileName)
{
lcDiskFile* File = new lcDiskFile(FileName);
mFile = File;
std::unique_ptr<lcDiskFile> File(new lcDiskFile(FileName));
if (!File->Open(QIODevice::WriteOnly))
return false;
mFile = std::move(File);
mNumEntries = 0;
mCentralDirSize = 0;
@ -61,13 +58,6 @@ bool lcZipFile::OpenWrite(const QString& FileName)
mBytesBeforeZipFile = 0;
mCentralPos = 0;
if (!File->Open(QIODevice::WriteOnly))
{
delete File;
mFile = nullptr;
return false;
}
return true;
}

View file

@ -58,7 +58,7 @@ public:
lcZipFile& operator=(lcZipFile&&) = delete;
bool OpenRead(const QString& FileName);
bool OpenRead(lcFile* File);
bool OpenRead(std::unique_ptr<lcFile> File);
bool OpenWrite(const QString& FileName);
bool ExtractFile(int FileIndex, lcMemFile& File, quint32 MaxLength = 0xffffffff);
@ -74,7 +74,7 @@ protected:
bool CheckFileCoherencyHeader(int FileIndex, quint32* SizeVar, quint64* OffsetLocalExtraField, quint32* SizeLocalExtraField);
QMutex mMutex;
lcFile* mFile;
std::unique_ptr<lcFile> mFile;
bool mModified;
bool mZip64;

View file

@ -32,16 +32,15 @@ lcLight::lcLight(float px, float py, float pz, float tx, float ty, float tz)
void lcLight::Initialize(const lcVector3& Position, const lcVector3& TargetPosition)
{
mState = 0;
memset(m_strName, 0, sizeof(m_strName));
ChangeKey(mPositionKeys, Position, 1, true);
ChangeKey(mTargetPositionKeys, TargetPosition, 1, true);
ChangeKey(mAmbientColorKeys, lcVector4(0.0f, 0.0f, 0.0f, 1.0f), 1, true);
ChangeKey(mDiffuseColorKeys, lcVector4(0.8f, 0.8f, 0.8f, 1.0f), 1, true);
ChangeKey(mSpecularColorKeys, lcVector4(1.0f, 1.0f, 1.0f, 1.0f), 1, true);
ChangeKey(mAttenuationKeys, lcVector3(1.0f, 0.0f, 0.0f), 1, true);
ChangeKey(mSpotCutoffKeys, 30.0f, 1, true);
ChangeKey(mSpotExponentKeys, 0.0f, 1, true);
mPositionKeys.ChangeKey(Position, 1, true);
mTargetPositionKeys.ChangeKey(TargetPosition, 1, true);
mAmbientColorKeys.ChangeKey(lcVector4(0.0f, 0.0f, 0.0f, 1.0f), 1, true);
mDiffuseColorKeys.ChangeKey(lcVector4(0.8f, 0.8f, 0.8f, 1.0f), 1, true);
mSpecularColorKeys.ChangeKey(lcVector4(1.0f, 1.0f, 1.0f, 1.0f), 1, true);
mAttenuationKeys.ChangeKey(lcVector3(1.0f, 0.0f, 0.0f), 1, true);
mSpotCutoffKeys.ChangeKey(30.0f, 1, true);
mSpotExponentKeys.ChangeKey(0.0f, 1, true);
}
lcLight::~lcLight()
@ -55,13 +54,13 @@ void lcLight::SaveLDraw(QTextStream& Stream) const
void lcLight::CreateName(const lcArray<lcLight*>& Lights)
{
if (m_strName[0])
if (!mName.isEmpty())
{
bool Found = false;
for (lcLight* Light : Lights)
{
if (!strcmp(Light->m_strName, m_strName))
if (Light->GetName() == mName)
{
Found = true;
break;
@ -72,21 +71,24 @@ void lcLight::CreateName(const lcArray<lcLight*>& Lights)
return;
}
int i, max = 0;
int MaxLightNumber = 0;
const QLatin1String Prefix("Light ");
for (lcLight* Light : Lights)
{
if (strncmp(Light->m_strName, "Light ", 6) == 0)
QString LightName = Light->GetName();
if (LightName.startsWith(Prefix))
{
if (sscanf(Light->m_strName + 6, " #%d", &i) == 1)
{
if (i > max)
max = i;
}
bool Ok = false;
int LightNumber = LightName.midRef(Prefix.size()).toInt(&Ok);
if (Ok && LightNumber > MaxLightNumber)
MaxLightNumber = LightNumber;
}
}
sprintf(m_strName, "Light #%.2d", max+1);
mName = Prefix + QString::number(MaxLightNumber + 1);
}
void lcLight::CompareBoundingBox(lcVector3& Min, lcVector3& Max)
@ -207,50 +209,50 @@ void lcLight::MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance)
if (IsSelected(LC_LIGHT_SECTION_POSITION))
{
mPosition += Distance;
ChangeKey(mPositionKeys, mPosition, Step, AddKey);
mPositionKeys.ChangeKey(mPosition, Step, AddKey);
}
if (IsSelected(LC_LIGHT_SECTION_TARGET))
{
mTargetPosition += Distance;
ChangeKey(mTargetPositionKeys, mTargetPosition, Step, AddKey);
mTargetPositionKeys.ChangeKey(mTargetPosition, Step, AddKey);
}
}
void lcLight::InsertTime(lcStep Start, lcStep Time)
{
lcObject::InsertTime(mPositionKeys, Start, Time);
lcObject::InsertTime(mTargetPositionKeys, Start, Time);
lcObject::InsertTime(mAmbientColorKeys, Start, Time);
lcObject::InsertTime(mDiffuseColorKeys, Start, Time);
lcObject::InsertTime(mSpecularColorKeys, Start, Time);
lcObject::InsertTime(mAttenuationKeys, Start, Time);
lcObject::InsertTime(mSpotCutoffKeys, Start, Time);
lcObject::InsertTime(mSpotExponentKeys, Start, Time);
mPositionKeys.InsertTime(Start, Time);
mTargetPositionKeys.InsertTime(Start, Time);
mAmbientColorKeys.InsertTime(Start, Time);
mDiffuseColorKeys.InsertTime(Start, Time);
mSpecularColorKeys.InsertTime(Start, Time);
mAttenuationKeys.InsertTime(Start, Time);
mSpotCutoffKeys.InsertTime(Start, Time);
mSpotExponentKeys.InsertTime(Start, Time);
}
void lcLight::RemoveTime(lcStep Start, lcStep Time)
{
lcObject::RemoveTime(mPositionKeys, Start, Time);
lcObject::RemoveTime(mTargetPositionKeys, Start, Time);
lcObject::RemoveTime(mAmbientColorKeys, Start, Time);
lcObject::RemoveTime(mDiffuseColorKeys, Start, Time);
lcObject::RemoveTime(mSpecularColorKeys, Start, Time);
lcObject::RemoveTime(mAttenuationKeys, Start, Time);
lcObject::RemoveTime(mSpotCutoffKeys, Start, Time);
lcObject::RemoveTime(mSpotExponentKeys, Start, Time);
mPositionKeys.RemoveTime(Start, Time);
mTargetPositionKeys.RemoveTime(Start, Time);
mAmbientColorKeys.RemoveTime(Start, Time);
mDiffuseColorKeys.RemoveTime(Start, Time);
mSpecularColorKeys.RemoveTime(Start, Time);
mAttenuationKeys.RemoveTime(Start, Time);
mSpotCutoffKeys.RemoveTime(Start, Time);
mSpotExponentKeys.RemoveTime(Start, Time);
}
void lcLight::UpdatePosition(lcStep Step)
{
mPosition = CalculateKey(mPositionKeys, Step);
mTargetPosition = CalculateKey(mTargetPositionKeys, Step);
mAmbientColor = CalculateKey(mAmbientColorKeys, Step);
mDiffuseColor = CalculateKey(mDiffuseColorKeys, Step);
mSpecularColor = CalculateKey(mSpecularColorKeys, Step);
mAttenuation = CalculateKey(mAttenuationKeys, Step);
mSpotCutoff = CalculateKey(mSpotCutoffKeys, Step);
mSpotExponent = CalculateKey(mSpotExponentKeys, Step);
mPosition = mPositionKeys.CalculateKey(Step);
mTargetPosition = mTargetPositionKeys.CalculateKey(Step);
mAmbientColor = mAmbientColorKeys.CalculateKey(Step);
mDiffuseColor = mDiffuseColorKeys.CalculateKey(Step);
mSpecularColor = mSpecularColorKeys.CalculateKey(Step);
mAttenuation = mAttenuationKeys.CalculateKey(Step);
mSpotCutoff = mSpotCutoffKeys.CalculateKey(Step);
mSpotExponent = mSpotExponentKeys.CalculateKey(Step);
if (IsPointLight())
{
@ -527,28 +529,28 @@ void lcLight::DrawPointLight(lcContext* Context) const
void lcLight::RemoveKeyFrames()
{
mPositionKeys.RemoveAll();
ChangeKey(mPositionKeys, mPosition, 1, true);
mPositionKeys.ChangeKey(mPosition, 1, true);
mTargetPositionKeys.RemoveAll();
ChangeKey(mTargetPositionKeys, mTargetPosition, 1, true);
mTargetPositionKeys.ChangeKey(mTargetPosition, 1, true);
mAmbientColorKeys.RemoveAll();
ChangeKey(mAmbientColorKeys, mAmbientColor, 1, true);
mAmbientColorKeys.ChangeKey(mAmbientColor, 1, true);
mDiffuseColorKeys.RemoveAll();
ChangeKey(mDiffuseColorKeys, mDiffuseColor, 1, true);
mDiffuseColorKeys.ChangeKey(mDiffuseColor, 1, true);
mSpecularColorKeys.RemoveAll();
ChangeKey(mSpecularColorKeys, mSpecularColor, 1, true);
mSpecularColorKeys.ChangeKey(mSpecularColor, 1, true);
mAttenuationKeys.RemoveAll();
ChangeKey(mAttenuationKeys, mAttenuation, 1, true);
mAttenuationKeys.ChangeKey(mAttenuation, 1, true);
mSpotCutoffKeys.RemoveAll();
ChangeKey(mSpotCutoffKeys, mSpotCutoff, 1, true);
mSpotCutoffKeys.ChangeKey(mSpotCutoff, 1, true);
mSpotExponentKeys.RemoveAll();
ChangeKey(mSpotExponentKeys, mSpotExponent, 1, true);
mSpotExponentKeys.ChangeKey(mSpotExponent, 1, true);
}
bool lcLight::Setup(int LightIndex)

View file

@ -191,8 +191,10 @@ public:
bool IsVisible() const
{ return (mState & LC_LIGHT_HIDDEN) == 0; }
const char* GetName() const override
{ return m_strName; }
QString GetName() const override
{
return mName;
}
void CompareBoundingBox(lcVector3& Min, lcVector3& Max);
void UpdatePosition(lcStep Step);
@ -212,21 +214,20 @@ public:
float mSpotExponent;
protected:
lcArray<lcObjectKey<lcVector3>> mPositionKeys;
lcArray<lcObjectKey<lcVector3>> mTargetPositionKeys;
lcArray<lcObjectKey<lcVector4>> mAmbientColorKeys;
lcArray<lcObjectKey<lcVector4>> mDiffuseColorKeys;
lcArray<lcObjectKey<lcVector4>> mSpecularColorKeys;
lcArray<lcObjectKey<lcVector3>> mAttenuationKeys;
lcArray<lcObjectKey<float>> mSpotCutoffKeys;
lcArray<lcObjectKey<float>> mSpotExponentKeys;
lcObjectKeyArray<lcVector3> mPositionKeys;
lcObjectKeyArray<lcVector3> mTargetPositionKeys;
lcObjectKeyArray<lcVector4> mAmbientColorKeys;
lcObjectKeyArray<lcVector4> mDiffuseColorKeys;
lcObjectKeyArray<lcVector4> mSpecularColorKeys;
lcObjectKeyArray<lcVector3> mAttenuationKeys;
lcObjectKeyArray<float> mSpotCutoffKeys;
lcObjectKeyArray<float> mSpotExponentKeys;
void Initialize(const lcVector3& Position, const lcVector3& TargetPosition);
void DrawPointLight(lcContext* Context) const;
void DrawSpotLight(lcContext* Context) const;
QString mName;
quint32 mState;
char m_strName[81];
};

View file

@ -1,16 +1,10 @@
#include "lc_global.h"
#include "lc_colors.h"
#include "lc_math.h"
#include <string.h>
#include <stdio.h>
#include "minifig.h"
#include "lc_colors.h"
#include "pieceinf.h"
#include "project.h"
#include "lc_model.h"
#include "lc_library.h"
#include "lc_application.h"
#include "lc_context.h"
#include "lc_scene.h"
#include "lc_file.h"
#include "lc_profile.h"
@ -36,15 +30,10 @@ const char* MinifigWizard::mSectionNames[LC_MFW_NUMITEMS] =
};
MinifigWizard::MinifigWizard()
: mModel(new lcModel(QString(), nullptr, false))
{
LoadSettings();
LoadTemplates();
mRotateX = 75.0f;
mRotateZ = 180.0f;
mDistance = 10.0f;
mAutoZoom = true;
mTracking = LC_TRACK_NONE;
}
MinifigWizard::~MinifigWizard()
@ -53,7 +42,7 @@ MinifigWizard::~MinifigWizard()
for (int i = 0; i < LC_MFW_NUMITEMS; i++)
if (mMinifig.Parts[i])
Library->ReleasePieceInfo(mMinifig.Parts[i]);
Library->ReleasePieceInfo(mMinifig.Parts[i]); // todo: don't call ReleasePieceInfo here because it may release textures and they need a GL context current
SaveTemplates();
}
@ -73,29 +62,15 @@ void MinifigWizard::LoadSettings()
}
}
QResource Resource(":/resources/minifig.ini");
lcDiskFile MinifigFile(":/resources/minifig.ini");
if (Resource.isValid())
{
QByteArray Data;
if (Resource.isCompressed())
Data = qUncompress(Resource.data(), Resource.size());
else
Data = QByteArray::fromRawData((const char*)Resource.data(), Resource.size());
lcMemFile MemSettings;
MemSettings.WriteBuffer(Data.constData(), Data.size());
ParseSettings(MemSettings);
}
if (MinifigFile.Open(QIODevice::ReadOnly))
ParseSettings(MinifigFile);
}
void MinifigWizard::OnInitialUpdate()
void MinifigWizard::LoadDefault()
{
MakeCurrent();
mContext->SetDefaultState();
static_assert(LC_ARRAY_COUNT(MinifigWizard::mSectionNames) == LC_MFW_NUMITEMS, "Array size mismatch.");
LC_ARRAY_SIZE_CHECK(MinifigWizard::mSectionNames, LC_MFW_NUMITEMS);
const int ColorCodes[LC_MFW_NUMITEMS] = { 4, 7, 14, 7, 1, 0, 7, 4, 4, 14, 14, 7, 7, 0, 0, 7, 7 };
const char* const Pieces[LC_MFW_NUMITEMS] = { "3624.dat", "", "3626bp01.dat", "", "973.dat", "3815.dat", "", "3819.dat", "3818.dat", "3820.dat", "3820.dat", "", "", "3817.dat", "3816.dat", "", "" };
@ -229,7 +204,6 @@ void MinifigWizard::DeleteTemplate(const QString& TemplateName)
void MinifigWizard::AddTemplatesJson(const QByteArray& TemplateData)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QJsonDocument Document = QJsonDocument::fromJson(TemplateData);
QJsonObject RootObject = Document.object();
@ -260,17 +234,10 @@ void MinifigWizard::AddTemplatesJson(const QByteArray& TemplateData)
mTemplates.emplace(ElementIt.key(), std::move(Template));
}
#endif
}
QByteArray MinifigWizard::GetTemplatesJson() const
{
QByteArray TemplateData;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QJsonObject RootObject;
RootObject["Version"] = 1;
QJsonObject TemplatesObject;
for (const auto& TemplateEntry : mTemplates)
@ -292,11 +259,11 @@ QByteArray MinifigWizard::GetTemplatesJson() const
TemplatesObject[TemplateEntry.first] = TemplateObject;
}
QJsonObject RootObject;
RootObject["Templates"] = TemplatesObject;
TemplateData = QJsonDocument(RootObject).toJson();
#endif
RootObject["Version"] = 1;
return TemplateData;
return QJsonDocument(RootObject).toJson();
}
void MinifigWizard::LoadTemplates()
@ -312,162 +279,9 @@ void MinifigWizard::LoadTemplates()
void MinifigWizard::SaveTemplates()
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QSettings Settings;
Settings.beginGroup("Minifig");
Settings.setValue("Templates", GetTemplatesJson());
#endif
}
void MinifigWizard::OnDraw()
{
mContext->SetDefaultState();
const float Aspect = (float)mWidth/(float)mHeight;
mContext->SetViewport(0, 0, mWidth, mHeight);
lcGetActiveModel()->DrawBackground(this);
lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX);
for (int InfoIdx = 0; InfoIdx < LC_MFW_NUMITEMS; InfoIdx++)
{
const PieceInfo* const Info = mMinifig.Parts[InfoIdx];
if (!Info)
continue;
lcVector3 Points[8];
lcGetBoxCorners(Info->GetBoundingBox(), Points);
for (int PointIdx = 0; PointIdx < 8; PointIdx++)
{
const lcVector3 Point = lcMul31(Points[PointIdx], mMinifig.Matrices[InfoIdx]);
Min = lcMin(Point, Min);
Max = lcMax(Point, Max);
}
}
const lcVector3 Center = (Min + Max) / 2.0f;
lcVector3 Eye(0.0f, 0.0f, 1.0f);
Eye = lcMul30(Eye, lcMatrix44RotationX(-mRotateX * LC_DTOR));
Eye = lcMul30(Eye, lcMatrix44RotationZ(-mRotateZ * LC_DTOR));
const lcMatrix44 Projection = lcMatrix44Perspective(30.0f, Aspect, 1.0f, 2500.0f);
mContext->SetProjectionMatrix(Projection);
lcMatrix44 ViewMatrix;
if (mAutoZoom)
{
lcVector3 Points[8];
lcGetBoxCorners(Min, Max, Points);
Eye += Center;
const lcMatrix44 ModelView = lcMatrix44LookAt(Eye, Center, lcVector3(0, 0, 1));
std::tie(Eye, std::ignore) = lcZoomExtents(Eye, ModelView, Projection, Points, 8);
ViewMatrix = lcMatrix44LookAt(Eye, Center, lcVector3(0, 0, 1));
const lcVector3 d = Eye - Center;
mDistance = d.Length();
}
else
{
ViewMatrix = lcMatrix44LookAt(Eye * mDistance, Center, lcVector3(0, 0, 1));
}
Calculate();
lcScene Scene;
Scene.Begin(ViewMatrix);
Scene.SetAllowLOD(false);
for (int PieceIdx = 0; PieceIdx < LC_MFW_NUMITEMS; PieceIdx++)
if (mMinifig.Parts[PieceIdx])
mMinifig.Parts[PieceIdx]->AddRenderMeshes(Scene, mMinifig.Matrices[PieceIdx], mMinifig.Colors[PieceIdx], lcRenderMeshState::Default, true);
Scene.End();
Scene.Draw(mContext);
mContext->ClearResources();
}
void MinifigWizard::OnLeftButtonDown()
{
if (mTracking == LC_TRACK_NONE)
{
mDownX = mInputState.x;
mDownY = mInputState.y;
mTracking = LC_TRACK_LEFT;
}
}
void MinifigWizard::OnLeftButtonUp()
{
if (mTracking == LC_TRACK_LEFT)
mTracking = LC_TRACK_NONE;
}
void MinifigWizard::OnLeftButtonDoubleClick()
{
mAutoZoom = true;
Redraw();
}
void MinifigWizard::OnRightButtonDown()
{
if (mTracking == LC_TRACK_NONE)
{
mDownX = mInputState.x;
mDownY = mInputState.y;
mTracking = LC_TRACK_RIGHT;
}
}
void MinifigWizard::OnRightButtonUp()
{
if (mTracking == LC_TRACK_RIGHT)
mTracking = LC_TRACK_NONE;
}
void MinifigWizard::OnMouseMove()
{
if (mTracking == LC_TRACK_LEFT)
{
// Rotate.
mRotateZ += mInputState.x - mDownX;
mRotateX += mInputState.y - mDownY;
if (mRotateX > 179.5f)
mRotateX = 179.5f;
else if (mRotateX < 0.5f)
mRotateX = 0.5f;
mDownX = mInputState.x;
mDownY = mInputState.y;
Redraw();
}
else if (mTracking == LC_TRACK_RIGHT)
{
// Zoom.
mDistance += (float)(mDownY - mInputState.y) * 0.2f;
mAutoZoom = false;
if (mDistance < 0.5f)
mDistance = 0.5f;
mDownX = mInputState.x;
mDownY = mInputState.y;
Redraw();
}
}
void MinifigWizard::Calculate()
@ -544,7 +358,7 @@ void MinifigWizard::Calculate()
if (Parts[LC_MFW_RHANDA])
{
Mat = lcMatrix44RotationZ(LC_DTOR * Angles[LC_MFW_RHANDA]);
Mat.SetTranslation(lcVector3(0, -10.0f, 0));
Mat.SetTranslation(lcVector3(0, -9.25f, 0));
Mat = lcMul(mSettings[LC_MFW_RHANDA][GetSelectionIndex(LC_MFW_RHANDA)].Offset, Mat);
Mat = lcMul(Mat, lcMatrix44RotationX(LC_DTOR * 15.0f));
Matrices[LC_MFW_RHANDA] = lcMul(Mat, Matrices[LC_MFW_RHAND]);
@ -578,7 +392,7 @@ void MinifigWizard::Calculate()
if (Parts[LC_MFW_LHANDA])
{
Mat = lcMatrix44RotationZ(LC_DTOR * Angles[LC_MFW_LHANDA]);
Mat.SetTranslation(lcVector3(0, -10.0f, 0));
Mat.SetTranslation(lcVector3(0, -9.25f, 0));
Mat = lcMul(mSettings[LC_MFW_LHANDA][GetSelectionIndex(LC_MFW_LHANDA)].Offset, Mat);
Mat = lcMul(Mat, lcMatrix44RotationX(LC_DTOR * 15.0f));
Matrices[LC_MFW_LHANDA] = lcMul(Mat, Matrices[LC_MFW_LHAND]);
@ -637,6 +451,8 @@ void MinifigWizard::Calculate()
Mat.SetTranslation(lcMul31(Center, Mat2));
Matrices[LC_MFW_LLEGA] = lcMul(Mat, Matrices[LC_MFW_LLEG]);
}
mModel->SetMinifig(mMinifig);
}
int MinifigWizard::GetSelectionIndex(int Type) const
@ -653,7 +469,6 @@ int MinifigWizard::GetSelectionIndex(int Type) const
void MinifigWizard::SetSelectionIndex(int Type, int Index)
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
MakeCurrent();
if (mMinifig.Parts[Type])
Library->ReleasePieceInfo(mMinifig.Parts[Type]);
@ -669,9 +484,13 @@ void MinifigWizard::SetSelectionIndex(int Type, int Index)
void MinifigWizard::SetColor(int Type, int Color)
{
mMinifig.Colors[Type] = Color;
Calculate();
}
void MinifigWizard::SetAngle(int Type, float Angle)
{
mMinifig.Angles[Type] = Angle;
Calculate();
}

View file

@ -1,6 +1,5 @@
#pragma once
#include "lc_glwidget.h"
#include "lc_math.h"
enum LC_MFW_TYPES
@ -47,16 +46,19 @@ struct lcMinifigTemplate
float Angles[LC_MFW_NUMITEMS];
};
class MinifigWizard : public lcGLWidget
class MinifigWizard
{
public:
MinifigWizard();
~MinifigWizard();
MinifigWizard(const MinifigWizard&) = delete;
MinifigWizard(MinifigWizard&&) = delete;
MinifigWizard& operator=(const MinifigWizard&) = delete;
MinifigWizard& operator=(MinifigWizard&&) = delete;
lcModel* GetModel() const
{
return mModel.get();
}
const std::map<QString, lcMinifigTemplate>& GetTemplates() const
{
@ -68,14 +70,7 @@ public:
void AddTemplatesJson(const QByteArray& TemplateData);
QByteArray GetTemplatesJson() const;
void OnDraw() override;
void OnLeftButtonDown() override;
void OnLeftButtonUp() override;
void OnLeftButtonDoubleClick() override;
void OnRightButtonDown() override;
void OnRightButtonUp() override;
void OnMouseMove() override;
void OnInitialUpdate() override;
void LoadDefault();
void Calculate();
int GetSelectionIndex(int Type) const;
@ -83,26 +78,18 @@ public:
void SetColor(int Type, int Color);
void SetAngle(int Type, float Angle);
void ParseSettings(lcFile& Settings);
std::vector<lcMinifigPieceInfo> mSettings[LC_MFW_NUMITEMS];
lcMinifig mMinifig;
int mTracking;
int mDownX;
int mDownY;
float mDistance;
float mRotateX;
float mRotateZ;
bool mAutoZoom;
protected:
void LoadSettings();
void ParseSettings(lcFile& Settings);
void LoadTemplates();
void SaveTemplates();
std::unique_ptr<lcModel> mModel;
std::map<QString, lcMinifigTemplate> mTemplates;
static const char* mSectionNames[LC_MFW_NUMITEMS];
};

View file

@ -1,6 +1,5 @@
#include "lc_global.h"
#include "object.h"
#include "lc_file.h"
lcObject::lcObject(lcObjectType ObjectType)
: mObjectType(ObjectType)
@ -10,3 +9,162 @@ lcObject::lcObject(lcObjectType ObjectType)
lcObject::~lcObject()
{
}
template void lcObjectKeyArray<float>::SaveKeysLDraw(QTextStream& Stream, const char* KeyName) const;
template void lcObjectKeyArray<float>::LoadKeysLDraw(QTextStream& Stream);
template const float& lcObjectKeyArray<float>::CalculateKey(lcStep Step) const;
template void lcObjectKeyArray<float>::ChangeKey(const float& Value, lcStep Step, bool AddKey);
template void lcObjectKeyArray<float>::InsertTime(lcStep Start, lcStep Time);
template void lcObjectKeyArray<float>::RemoveTime(lcStep Start, lcStep Time);
template void lcObjectKeyArray<lcVector3>::SaveKeysLDraw(QTextStream& Stream, const char* KeyName) const;
template void lcObjectKeyArray<lcVector3>::LoadKeysLDraw(QTextStream& Stream);
template const lcVector3& lcObjectKeyArray<lcVector3>::CalculateKey(lcStep Step) const;
template void lcObjectKeyArray<lcVector3>::ChangeKey(const lcVector3& Value, lcStep Step, bool AddKey);
template void lcObjectKeyArray<lcVector3>::InsertTime(lcStep Start, lcStep Time);
template void lcObjectKeyArray<lcVector3>::RemoveTime(lcStep Start, lcStep Time);
template void lcObjectKeyArray<lcVector4>::SaveKeysLDraw(QTextStream& Stream, const char* KeyName) const;
template void lcObjectKeyArray<lcVector4>::LoadKeysLDraw(QTextStream& Stream);
template const lcVector4& lcObjectKeyArray<lcVector4>::CalculateKey(lcStep Step) const;
template void lcObjectKeyArray<lcVector4>::ChangeKey(const lcVector4& Value, lcStep Step, bool AddKey);
template void lcObjectKeyArray<lcVector4>::InsertTime(lcStep Start, lcStep Time);
template void lcObjectKeyArray<lcVector4>::RemoveTime(lcStep Start, lcStep Time);
template void lcObjectKeyArray<lcMatrix33>::SaveKeysLDraw(QTextStream& Stream, const char* KeyName) const;
template void lcObjectKeyArray<lcMatrix33>::LoadKeysLDraw(QTextStream& Stream);
template const lcMatrix33& lcObjectKeyArray<lcMatrix33>::CalculateKey(lcStep Step) const;
template void lcObjectKeyArray<lcMatrix33>::ChangeKey(const lcMatrix33& Value, lcStep Step, bool AddKey);
template void lcObjectKeyArray<lcMatrix33>::InsertTime(lcStep Start, lcStep Time);
template void lcObjectKeyArray<lcMatrix33>::RemoveTime(lcStep Start, lcStep Time);
template<typename T>
void lcObjectKeyArray<T>::SaveKeysLDraw(QTextStream& Stream, const char* KeyName) const
{
const int Count = sizeof(T) / sizeof(float);
for (const lcObjectKey<T>& Key : mKeys)
{
Stream << QLatin1String("0 !LEOCAD ") << KeyName << Key.Step << ' ';
for (int ValueIdx = 0; ValueIdx < Count; ValueIdx++)
Stream << ((float*)&Key.Value)[ValueIdx] << ' ';
Stream << QLatin1String("\r\n");
}
}
template<typename T>
void lcObjectKeyArray<T>::LoadKeysLDraw(QTextStream& Stream)
{
QString Token;
Stream >> Token;
int Step = Token.toInt();
T Value;
const int Count = sizeof(T) / sizeof(float);
for (int ValueIdx = 0; ValueIdx < Count; ValueIdx++)
Stream >> ((float*)&Value)[ValueIdx];
ChangeKey(Value, Step, true);
}
template<typename T>
const T& lcObjectKeyArray<T>::CalculateKey(lcStep Step) const
{
const lcObjectKey<T>* PreviousKey = &mKeys[0];
for (const lcObjectKey<T>& Key : mKeys)
{
if (Key.Step > Step)
break;
PreviousKey = &Key;
}
return PreviousKey->Value;
}
template<typename T>
void lcObjectKeyArray<T>::ChangeKey(const T& Value, lcStep Step, bool AddKey)
{
for (typename std::vector<lcObjectKey<T>>::iterator KeyIt = mKeys.begin(); KeyIt != mKeys.end(); KeyIt++)
{
if (KeyIt->Step < Step)
continue;
if (KeyIt->Step == Step)
KeyIt->Value = Value;
else if (AddKey)
mKeys.insert(KeyIt, lcObjectKey<T>{ Step, Value });
else if (KeyIt == mKeys.begin())
KeyIt->Value = Value;
else
{
KeyIt = KeyIt - 1;
KeyIt->Value = Value;
}
return;
}
if (AddKey || mKeys.empty())
mKeys.emplace_back(lcObjectKey<T>{ Step, Value });
else
mKeys.back().Value = Value;
}
template<typename T>
void lcObjectKeyArray<T>::InsertTime(lcStep Start, lcStep Time)
{
bool EndKey = false;
for (typename std::vector<lcObjectKey<T>>::iterator KeyIt = mKeys.begin(); KeyIt != mKeys.end();)
{
if ((KeyIt->Step < Start) || (KeyIt->Step == 1))
{
KeyIt++;
continue;
}
if (EndKey)
{
KeyIt = mKeys.erase(KeyIt);
continue;
}
if (KeyIt->Step >= LC_STEP_MAX - Time)
{
KeyIt->Step = LC_STEP_MAX;
EndKey = true;
}
else
KeyIt->Step += Time;
KeyIt++;
}
}
template<typename T>
void lcObjectKeyArray<T>::RemoveTime(lcStep Start, lcStep Time)
{
for (typename std::vector<lcObjectKey<T>>::iterator KeyIt = mKeys.begin(); KeyIt != mKeys.end();)
{
if ((KeyIt->Step < Start) || (KeyIt->Step == 1))
{
KeyIt++;
continue;
}
if (KeyIt->Step < Start + Time)
{
KeyIt = mKeys.erase(KeyIt);
continue;
}
KeyIt->Step -= Time;
KeyIt++;
}
}

View file

@ -3,9 +3,6 @@
#include "lc_math.h"
#include "lc_array.h"
typedef quint32 lcStep;
#define LC_STEP_MAX 0xffffffff
enum class lcObjectType
{
Piece,
@ -20,6 +17,36 @@ struct lcObjectKey
T Value;
};
template<typename T>
class lcObjectKeyArray
{
public:
int GetSize() const
{
return static_cast<int>(mKeys.size());
}
bool IsEmpty() const
{
return mKeys.empty();
}
void RemoveAll()
{
mKeys.clear();
}
void SaveKeysLDraw(QTextStream& Stream, const char* KeyName) const;
void LoadKeysLDraw(QTextStream& Stream);
const T& CalculateKey(lcStep Step) const;
void ChangeKey(const T& Value, lcStep Step, bool AddKey);
void InsertTime(lcStep Start, lcStep Time);
void RemoveTime(lcStep Start, lcStep Time);
protected:
std::vector<lcObjectKey<T>> mKeys;
};
struct lcObjectSection
{
lcObject* Object;
@ -61,9 +88,7 @@ public:
virtual ~lcObject();
lcObject(const lcObject&) = delete;
lcObject(lcObject&&) = delete;
lcObject& operator=(const lcObject&) = delete;
lcObject& operator=(lcObject&&) = delete;
public:
bool IsPiece() const
@ -101,148 +126,7 @@ public:
virtual void BoxTest(lcObjectBoxTest& ObjectBoxTest) const = 0;
virtual void DrawInterface(lcContext* Context, const lcScene& Scene) const = 0;
virtual void RemoveKeyFrames() = 0;
virtual const char* GetName() const = 0;
protected:
template<typename T>
void SaveKeysLDraw(QTextStream& Stream, const lcArray<lcObjectKey<T>>& Keys, const char* KeyName) const
{
const int Count = sizeof(T) / sizeof(float);
for (int KeyIdx = 0; KeyIdx < Keys.GetSize(); KeyIdx++)
{
const lcObjectKey<T>& Key = Keys[KeyIdx];
Stream << QLatin1String("0 !LEOCAD ") << KeyName << Key.Step << ' ';
for (int ValueIdx = 0; ValueIdx < Count; ValueIdx++)
Stream << ((float*)&Key.Value)[ValueIdx] << ' ';
Stream << QLatin1String("\r\n");
}
}
template<typename T>
void LoadKeysLDraw(QTextStream& Stream, lcArray<lcObjectKey<T>>& Keys)
{
QString Token;
Stream >> Token;
int Step = Token.toInt();
T Value;
const int Count = sizeof(T) / sizeof(float);
for (int ValueIdx = 0; ValueIdx < Count; ValueIdx++)
Stream >> ((float*)&Value)[ValueIdx];
ChangeKey(Keys, Value, Step, true);
}
template<typename T>
const T& CalculateKey(const lcArray<lcObjectKey<T>>& Keys, lcStep Step)
{
const lcObjectKey<T>* PreviousKey = &Keys[0];
for (int KeyIdx = 0; KeyIdx < Keys.GetSize(); KeyIdx++)
{
if (Keys[KeyIdx].Step > Step)
break;
PreviousKey = &Keys[KeyIdx];
}
return PreviousKey->Value;
}
template<typename T>
void ChangeKey(lcArray<lcObjectKey<T>>& Keys, const T& Value, lcStep Step, bool AddKey)
{
for (int KeyIdx = 0; KeyIdx < Keys.GetSize(); KeyIdx++)
{
lcObjectKey<T>* Key = &Keys[KeyIdx];
if (Key->Step == Step)
{
Key->Value = Value;
return;
}
if (Key->Step > Step)
{
if (AddKey)
{
Key = &Keys.InsertAt(KeyIdx);
Key->Step = Step;
}
else if (KeyIdx)
Key = &Keys[KeyIdx - 1];
Key->Value = Value;
return;
}
}
if (AddKey || Keys.GetSize() == 0)
{
lcObjectKey<T>* Key = &Keys.Add();
Key->Step = Step;
Key->Value = Value;
}
else
{
lcObjectKey<T>* Key = &Keys[Keys.GetSize() - 1];
Key->Value = Value;
}
}
template<typename T>
void InsertTime(lcArray<lcObjectKey<T>>& Keys, lcStep Start, lcStep Time)
{
bool EndKey = false;
for (int KeyIdx = 0; KeyIdx < Keys.GetSize(); KeyIdx++)
{
lcObjectKey<T>& Key = Keys[KeyIdx];
if ((Key.Step < Start) || (Key.Step == 1))
continue;
if (EndKey)
{
Keys.RemoveIndex(KeyIdx);
KeyIdx--;
continue;
}
if (Key.Step >= LC_STEP_MAX - Time)
{
Key.Step = LC_STEP_MAX;
EndKey = true;
}
else
Key.Step += Time;
}
}
template<typename T>
void RemoveTime(lcArray<lcObjectKey<T>>& Keys, lcStep Start, lcStep Time)
{
for (int KeyIdx = 0; KeyIdx < Keys.GetSize(); KeyIdx++)
{
lcObjectKey<T>& Key = Keys[KeyIdx];
if ((Key.Step < Start) || (Key.Step == 1))
continue;
if (Key.Step < Start + Time)
{
Keys.RemoveIndex(KeyIdx);
KeyIdx--;
continue;
}
Key.Step -= Time;
}
}
virtual QString GetName() const = 0;
private:
lcObjectType mObjectType;

View file

@ -123,10 +123,10 @@ void lcPiece::SaveLDraw(QTextStream& Stream) const
}
if (mPositionKeys.GetSize() > 1)
SaveKeysLDraw(Stream, mPositionKeys, "PIECE POSITION_KEY ");
mPositionKeys.SaveKeysLDraw(Stream, "PIECE POSITION_KEY ");
if (mRotationKeys.GetSize() > 1)
SaveKeysLDraw(Stream, mRotationKeys, "PIECE ROTATION_KEY ");
mRotationKeys.SaveKeysLDraw(Stream, "PIECE ROTATION_KEY ");
Stream << "1 " << mColorCode << ' ';
@ -163,9 +163,9 @@ bool lcPiece::ParseLDrawLine(QTextStream& Stream)
mState |= LC_PIECE_PIVOT_POINT_VALID;
}
else if (Token == QLatin1String("POSITION_KEY"))
LoadKeysLDraw(Stream, mPositionKeys);
mPositionKeys.LoadKeysLDraw(Stream);
else if (Token == QLatin1String("ROTATION_KEY"))
LoadKeysLDraw(Stream, mRotationKeys);
mRotationKeys.LoadKeysLDraw(Stream);
}
return false;
@ -180,6 +180,8 @@ bool lcPiece::FileLoad(lcFile& file)
if (version > 12) // LeoCAD 0.80
return false;
const float PositionScale = (version < 12) ? 25.0f : 1.0f;
if (version > 8)
{
if (file.ReadU8() != 1)
@ -198,9 +200,9 @@ bool lcPiece::FileLoad(lcFile& file)
file.ReadU8(&type, 1);
if (type == 0)
ChangeKey(mPositionKeys, lcVector3(param[0], param[1], param[2]), time, true);
mPositionKeys.ChangeKey(lcVector3(param[0], param[1], param[2]) * PositionScale, time, true);
else if (type == 1)
ChangeKey(mRotationKeys, lcMatrix33FromAxisAngle(lcVector3(param[0], param[1], param[2]), param[3] * LC_DTOR), time, true);
mRotationKeys.ChangeKey(lcMatrix33FromAxisAngle(lcVector3(param[0], param[1], param[2]), param[3] * LC_DTOR), time, true);
}
file.ReadU32(&n, 1);
@ -212,50 +214,71 @@ bool lcPiece::FileLoad(lcFile& file)
}
}
if (version < 9)
{
quint16 time;
quint8 type;
if (version < 9)
{
quint16 time;
quint8 type;
if (version > 5)
{
quint32 keys;
float param[4];
if (version > 5)
{
quint32 keys;
float param[4];
file.ReadU32(&keys, 1);
while (keys--)
{
file.ReadFloats(param, 4);
file.ReadU16(&time, 1);
file.ReadU8(&type, 1);
if (type == 0)
ChangeKey(mPositionKeys, lcVector3(param[0], param[1], param[2]), time, true);
else if (type == 1)
ChangeKey(mRotationKeys, lcMatrix33FromAxisAngle(lcVector3(param[0], param[1], param[2]), param[3] * LC_DTOR), time, true);
}
file.ReadU32(&keys, 1);
while (keys--)
{
file.ReadFloats(param, 4);
file.ReadU16(&time, 1);
file.ReadU8(&type, 1);
}
}
else
{
if (version > 2)
{
file.ReadU8(&ch, 1);
while (ch--)
{
lcMatrix44 ModelWorld;
if (version > 3)
file.ReadU32(&keys, 1);
while (keys--)
{
file.ReadFloats(ModelWorld, 16);
file.ReadFloats(param, 4);
file.ReadU16(&time, 1);
file.ReadU8(&type, 1);
if (type == 0)
mPositionKeys.ChangeKey(lcVector3(param[0], param[1], param[2]) * PositionScale, time, true);
else if (type == 1)
mRotationKeys.ChangeKey(lcMatrix33FromAxisAngle(lcVector3(param[0], param[1], param[2]), param[3] * LC_DTOR), time, true);
}
file.ReadU32(&keys, 1);
while (keys--)
{
file.ReadFloats(param, 4);
file.ReadU16(&time, 1);
file.ReadU8(&type, 1);
}
}
else
{
if (version > 2)
{
file.ReadU8(&ch, 1);
while (ch--)
{
lcMatrix44 ModelWorld;
if (version > 3)
{
file.ReadFloats(ModelWorld, 16);
}
else
{
lcVector3 Translation;
float Rotation[3];
file.ReadFloats(Translation, 3);
file.ReadFloats(Rotation, 3);
ModelWorld = lcMatrix44Translation(Translation);
ModelWorld = lcMul(lcMatrix44RotationZ(Rotation[2] * LC_DTOR), lcMul(lcMatrix44RotationY(Rotation[1] * LC_DTOR), lcMul(lcMatrix44RotationX(Rotation[0] * LC_DTOR), ModelWorld)));
}
quint8 b;
file.ReadU8(&b, 1);
time = b;
mPositionKeys.ChangeKey(ModelWorld.GetTranslation() * PositionScale, 1, true);
mRotationKeys.ChangeKey(lcMatrix33(ModelWorld), time, true);
qint32 bl;
file.ReadS32(&bl, 1);
}
}
else
{
@ -263,46 +286,25 @@ bool lcPiece::FileLoad(lcFile& file)
float Rotation[3];
file.ReadFloats(Translation, 3);
file.ReadFloats(Rotation, 3);
ModelWorld = lcMatrix44Translation(Translation);
lcMatrix44 ModelWorld = lcMatrix44Translation(Translation);
ModelWorld = lcMul(lcMatrix44RotationZ(Rotation[2] * LC_DTOR), lcMul(lcMatrix44RotationY(Rotation[1] * LC_DTOR), lcMul(lcMatrix44RotationX(Rotation[0] * LC_DTOR), ModelWorld)));
mPositionKeys.ChangeKey(lcVector3(ModelWorld.r[3][0], ModelWorld.r[3][1], ModelWorld.r[3][2]) * PositionScale, 1, true);
mRotationKeys.ChangeKey(lcMatrix33(ModelWorld), 1, true);
}
}
}
quint8 b;
file.ReadU8(&b, 1);
time = b;
ChangeKey(mPositionKeys, ModelWorld.GetTranslation(), 1, true);
ChangeKey(mRotationKeys, lcMatrix33(ModelWorld), time, true);
qint32 bl;
file.ReadS32(&bl, 1);
}
}
else
{
lcVector3 Translation;
float Rotation[3];
file.ReadFloats(Translation, 3);
file.ReadFloats(Rotation, 3);
lcMatrix44 ModelWorld = lcMatrix44Translation(Translation);
ModelWorld = lcMul(lcMatrix44RotationZ(Rotation[2] * LC_DTOR), lcMul(lcMatrix44RotationY(Rotation[1] * LC_DTOR), lcMul(lcMatrix44RotationX(Rotation[0] * LC_DTOR), ModelWorld)));
ChangeKey(mPositionKeys, lcVector3(ModelWorld.r[3][0], ModelWorld.r[3][1], ModelWorld.r[3][2]), 1, true);
ChangeKey(mRotationKeys, lcMatrix33(ModelWorld), 1, true);
}
}
}
// Common to all versions.
// Common to all versions.
char name[LC_PIECE_NAME_LEN];
if (version < 10)
{
memset(name, 0, LC_PIECE_NAME_LEN);
file.ReadBuffer(name, 9);
}
else
file.ReadBuffer(name, LC_PIECE_NAME_LEN);
strcat(name, ".dat");
if (version < 10)
{
memset(name, 0, LC_PIECE_NAME_LEN);
file.ReadBuffer(name, 9);
}
else
file.ReadBuffer(name, LC_PIECE_NAME_LEN);
strcat(name, ".dat");
PieceInfo* pInfo = lcGetPiecesLibrary()->FindPiece(name, nullptr, true, false);
SetPieceInfo(pInfo, QString(), true);
@ -323,63 +325,57 @@ bool lcPiece::FileLoad(lcFile& file)
file.ReadU32(&mColorCode, 1);
mColorIndex = lcGetColorIndex(mColorCode);
quint8 Step;
file.ReadU8(&Step, 1);
mStepShow = Step;
if (version > 1)
{
file.ReadU8(&Step, 1);
mStepHide = Step == 255 ? LC_STEP_MAX : Step;
}
else
mStepHide = LC_STEP_MAX;
if (version > 5)
{
file.ReadU16(); // m_nFrameShow
file.ReadU16(); // m_nFrameHide
if (version > 7)
{
quint8 Hidden;
file.ReadU8(&Hidden, 1);
if (Hidden & 1)
mState |= LC_PIECE_HIDDEN;
file.ReadU8(&ch, 1);
file.Seek(ch, SEEK_CUR);
}
else
{
qint32 hide;
file.ReadS32(&hide, 1);
if (hide != 0)
mState |= LC_PIECE_HIDDEN;
file.Seek(81, SEEK_CUR);
}
// 7 (0.64)
qint32 i = -1;
if (version > 6)
file.ReadS32(&i, 1);
mGroup = (lcGroup*)(quintptr)i;
}
else
{
file.ReadU8(&ch, 1);
if (ch == 0)
mGroup = (lcGroup*)-1;
else
mGroup = (lcGroup*)(quintptr)ch;
file.ReadU8(&ch, 1);
if (ch & 0x01)
mState |= LC_PIECE_HIDDEN;
}
if (version < 12)
quint8 Step;
file.ReadU8(&Step, 1);
mStepShow = Step;
if (version > 1)
{
for (int KeyIdx = 0; KeyIdx < mPositionKeys.GetSize(); KeyIdx++)
mPositionKeys[KeyIdx].Value *= 25.0f;
file.ReadU8(&Step, 1);
mStepHide = Step == 255 ? LC_STEP_MAX : Step;
}
else
mStepHide = LC_STEP_MAX;
if (version > 5)
{
file.ReadU16(); // m_nFrameShow
file.ReadU16(); // m_nFrameHide
if (version > 7)
{
quint8 Hidden;
file.ReadU8(&Hidden, 1);
if (Hidden & 1)
mState |= LC_PIECE_HIDDEN;
file.ReadU8(&ch, 1);
file.Seek(ch, SEEK_CUR);
}
else
{
qint32 hide;
file.ReadS32(&hide, 1);
if (hide != 0)
mState |= LC_PIECE_HIDDEN;
file.Seek(81, SEEK_CUR);
}
// 7 (0.64)
qint32 i = -1;
if (version > 6)
file.ReadS32(&i, 1);
mGroup = (lcGroup*)(quintptr)i;
}
else
{
file.ReadU8(&ch, 1);
if (ch == 0)
mGroup = (lcGroup*)-1;
else
mGroup = (lcGroup*)(quintptr)ch;
file.ReadU8(&ch, 1);
if (ch & 0x01)
mState |= LC_PIECE_HIDDEN;
}
return true;
@ -390,9 +386,9 @@ void lcPiece::Initialize(const lcMatrix44& WorldMatrix, lcStep Step)
mStepShow = Step;
if (mPositionKeys.IsEmpty())
ChangeKey(mPositionKeys, WorldMatrix.GetTranslation(), 1, true);
mPositionKeys.ChangeKey(WorldMatrix.GetTranslation(), 1, true);
if (mRotationKeys.IsEmpty())
ChangeKey(mRotationKeys, lcMatrix33(WorldMatrix), 1, true);
mRotationKeys.ChangeKey(lcMatrix33(WorldMatrix), 1, true);
UpdatePosition(Step);
}
@ -426,8 +422,8 @@ void lcPiece::InsertTime(lcStep Start, lcStep Time)
}
}
lcObject::InsertTime(mPositionKeys, Start, Time);
lcObject::InsertTime(mRotationKeys, Start, Time);
mPositionKeys.InsertTime(Start, Time);
mRotationKeys.InsertTime(Start, Time);
}
void lcPiece::RemoveTime(lcStep Start, lcStep Time)
@ -459,8 +455,8 @@ void lcPiece::RemoveTime(lcStep Start, lcStep Time)
}
}
lcObject::RemoveTime(mPositionKeys, Start, Time);
lcObject::RemoveTime(mRotationKeys, Start, Time);
mPositionKeys.RemoveTime(Start, Time);
mRotationKeys.RemoveTime(Start, Time);
}
void lcPiece::RayTest(lcObjectRayTest& ObjectRayTest) const
@ -617,7 +613,7 @@ void lcPiece::DrawInterface(lcContext* Context, const lcScene& Scene) const
};
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
Context->EnableCullFace(true);
for (int ControlPointIdx = 0; ControlPointIdx < mControlPoints.GetSize(); ControlPointIdx++)
{
@ -635,7 +631,7 @@ void lcPiece::DrawInterface(lcContext* Context, const lcScene& Scene) const
Context->DrawIndexedPrimitives(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
}
glDisable(GL_CULL_FACE);
Context->EnableCullFace(false);
glDisable(GL_BLEND);
}
}
@ -643,13 +639,13 @@ void lcPiece::DrawInterface(lcContext* Context, const lcScene& Scene) const
void lcPiece::RemoveKeyFrames()
{
mPositionKeys.RemoveAll();
ChangeKey(mPositionKeys, mModelWorld.GetTranslation(), 1, true);
mPositionKeys.ChangeKey(mModelWorld.GetTranslation(), 1, true);
mRotationKeys.RemoveAll();
ChangeKey(mRotationKeys, lcMatrix33(mModelWorld), 1, true);
mRotationKeys.ChangeKey(lcMatrix33(mModelWorld), 1, true);
}
void lcPiece::AddMainModelRenderMeshes(lcScene& Scene, bool Highlight, bool Fade) const
void lcPiece::AddMainModelRenderMeshes(lcScene* Scene, bool Highlight, bool Fade) const
{
lcRenderMeshState RenderMeshState = lcRenderMeshState::Default;
bool ParentActive = false;
@ -660,9 +656,9 @@ void lcPiece::AddMainModelRenderMeshes(lcScene& Scene, bool Highlight, bool Fade
if (Fade)
RenderMeshState = lcRenderMeshState::Faded;
if (Scene.GetDrawInterface())
if (Scene->GetDrawInterface())
{
lcPiece* ActiveSubmodelInstance = Scene.GetActiveSubmodelInstance();
lcPiece* ActiveSubmodelInstance = Scene->GetActiveSubmodelInstance();
if (!ActiveSubmodelInstance)
RenderMeshState = IsFocused() ? lcRenderMeshState::Focused : (IsSelected() ? lcRenderMeshState::Selected : RenderMeshState);
@ -675,20 +671,20 @@ void lcPiece::AddMainModelRenderMeshes(lcScene& Scene, bool Highlight, bool Fade
if (!mMesh)
mPieceInfo->AddRenderMeshes(Scene, mModelWorld, mColorIndex, RenderMeshState, ParentActive);
else
Scene.AddMesh(mMesh, mModelWorld, mColorIndex, RenderMeshState);
Scene->AddMesh(mMesh, mModelWorld, mColorIndex, RenderMeshState);
if (RenderMeshState == lcRenderMeshState::Focused || RenderMeshState == lcRenderMeshState::Selected)
Scene.AddInterfaceObject(this);
Scene->AddInterfaceObject(this);
}
void lcPiece::AddSubModelRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const
void lcPiece::AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const
{
int ColorIndex = mColorIndex;
if (ColorIndex == gDefaultColor)
ColorIndex = DefaultColorIndex;
lcPiece* ActiveSubmodelInstance = Scene.GetActiveSubmodelInstance();
lcPiece* ActiveSubmodelInstance = Scene->GetActiveSubmodelInstance();
if (ActiveSubmodelInstance == this)
RenderMeshState = lcRenderMeshState::Default;
@ -698,17 +694,32 @@ void lcPiece::AddSubModelRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMat
if (!mMesh)
mPieceInfo->AddRenderMeshes(Scene, lcMul(mModelWorld, WorldMatrix), ColorIndex, RenderMeshState, ActiveSubmodelInstance == this);
else
Scene.AddMesh(mMesh, lcMul(mModelWorld, WorldMatrix), ColorIndex, RenderMeshState);
Scene->AddMesh(mMesh, lcMul(mModelWorld, WorldMatrix), ColorIndex, RenderMeshState);
if (ParentActive && (RenderMeshState == lcRenderMeshState::Focused || RenderMeshState == lcRenderMeshState::Selected))
Scene.AddInterfaceObject(this);
Scene->AddInterfaceObject(this);
}
void lcPiece::SubmodelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const
void lcPiece::SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const
{
mPieceInfo->CompareBoundingBox(lcMul(mModelWorld, WorldMatrix), Min, Max);
}
void lcPiece::SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const
{
if (!mMesh)
mPieceInfo->AddSubModelBoundingBoxPoints(lcMul(mModelWorld, WorldMatrix), Points);
else
{
lcVector3 BoxPoints[8];
lcGetBoxCorners(mMesh->mBoundingBox, BoxPoints);
for (int i = 0; i < 8; i++)
Points.emplace_back(lcMul31(BoxPoints[i], mModelWorld));
}
}
void lcPiece::MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance)
{
quint32 Section = GetFocusSection();
@ -896,9 +907,9 @@ void lcPiece::VerifyControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) c
}
}
const char* lcPiece::GetName() const
QString lcPiece::GetName() const
{
return mPieceInfo->m_strDescription;
return QString::fromLatin1(mPieceInfo->m_strDescription);
}
bool lcPiece::IsVisible(lcStep Step) const
@ -965,8 +976,8 @@ lcGroup* lcPiece::GetTopGroup()
void lcPiece::UpdatePosition(lcStep Step)
{
lcVector3 Position = CalculateKey(mPositionKeys, Step);
lcMatrix33 Rotation = CalculateKey(mRotationKeys, Step);
lcVector3 Position = mPositionKeys.CalculateKey(Step);
lcMatrix33 Rotation = mRotationKeys.CalculateKey(Step);
mModelWorld = lcMatrix44(Rotation, Position);
}

View file

@ -409,9 +409,10 @@ public:
void DrawInterface(lcContext* Context, const lcScene& Scene) const override;
void RemoveKeyFrames() override;
void AddMainModelRenderMeshes(lcScene& Scene, bool Highlight, bool Fade) const;
void AddSubModelRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
void SubmodelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const;
void AddMainModelRenderMeshes(lcScene* Scene, bool Highlight, bool Fade) const;
void AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
void SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const;
void SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const;
void InsertTime(lcStep Start, lcStep Time);
void RemoveTime(lcStep Start, lcStep Time);
@ -453,7 +454,7 @@ public:
void UpdateID();
const char* GetName() const override;
QString GetName() const override;
bool IsVisible(lcStep Step) const;
bool IsVisibleInSubModel() const;
void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector<lcModelPartsEntry>& ModelParts) const;
@ -524,12 +525,22 @@ public:
mStepHide = mStepShow + 1;
}
quint32 GetColorCode() const
{
return mColorCode;
}
void SetColorCode(quint32 ColorCode)
{
mColorCode = ColorCode;
mColorIndex = lcGetColorIndex(ColorCode);
}
int GetColorIndex() const
{
return mColorIndex;
}
void SetColorIndex(int ColorIndex)
{
mColorIndex = ColorIndex;
@ -538,12 +549,12 @@ public:
void SetPosition(const lcVector3& Position, lcStep Step, bool AddKey)
{
ChangeKey(mPositionKeys, Position, Step, AddKey);
mPositionKeys.ChangeKey(Position, Step, AddKey);
}
void SetRotation(const lcMatrix33& Rotation, lcStep Step, bool AddKey)
{
ChangeKey(mRotationKeys, Rotation, Step, AddKey);
mRotationKeys.ChangeKey(Rotation, Step, AddKey);
}
lcVector3 GetRotationCenter() const
@ -605,9 +616,6 @@ public:
public:
PieceInfo* mPieceInfo;
int mColorIndex;
quint32 mColorCode;
lcMatrix44 mModelWorld;
lcMatrix44 mPivotMatrix;
@ -624,14 +632,17 @@ protected:
return IsSelected();
}
lcArray<lcObjectKey<lcVector3>> mPositionKeys;
lcArray<lcObjectKey<lcMatrix33>> mRotationKeys;
lcObjectKeyArray<lcVector3> mPositionKeys;
lcObjectKeyArray<lcMatrix33> mRotationKeys;
int mFileLine;
QString mID;
lcGroup* mGroup;
int mColorIndex;
quint32 mColorCode;
lcStep mStepShow;
lcStep mStepHide;

View file

@ -16,7 +16,7 @@
PieceInfo::PieceInfo()
{
mZipFileType = LC_NUM_ZIPFILES;
mZipFileType = lcZipFileType::Count;
mZipFileIndex = -1;
mState = LC_PIECEINFO_UNLOADED;
mRefCount = 0;
@ -44,9 +44,9 @@ void PieceInfo::SetMesh(lcMesh* Mesh)
void PieceInfo::SetPlaceholder()
{
mBoundingBox.Min = lcVector3(-10.0f, -10.0f, -24.0f);
mBoundingBox.Max = lcVector3(10.0f, 10.0f, 4.0f);
ReleaseMesh();
lcMesh* Mesh = new lcMesh;
Mesh->CreateBox();
SetMesh(Mesh);
mType = lcPieceInfoType::Placeholder;
mModel = nullptr;
@ -59,11 +59,13 @@ void PieceInfo::SetModel(lcModel* Model, bool UpdateMesh, Project* CurrentProjec
{
mType = lcPieceInfoType::Model;
mModel = Model;
delete mMesh;
mMesh = nullptr;
}
strncpy(mFileName, Model->GetProperties().mFileName.toLatin1().data(), sizeof(mFileName));
strncpy(mFileName, Model->GetProperties().mFileName.toLatin1().data(), sizeof(mFileName) - 1);
mFileName[sizeof(mFileName)-1] = 0;
strncpy(m_strDescription, Model->GetProperties().mFileName.toLatin1().data(), sizeof(m_strDescription));
strncpy(m_strDescription, Model->GetProperties().mFileName.toLatin1().data(), sizeof(m_strDescription) - 1);
m_strDescription[sizeof(m_strDescription)-1] = 0;
const QStringList& MeshLines = Model->GetFileLines();
@ -100,9 +102,9 @@ void PieceInfo::CreateProject(Project* Project, const char* PieceName)
mState = LC_PIECEINFO_LOADED;
}
strncpy(mFileName, PieceName, sizeof(mFileName));
strncpy(mFileName, PieceName, sizeof(mFileName) - 1);
mFileName[sizeof(mFileName) - 1] = 0;
strncpy(m_strDescription, Project->GetFileName().toLatin1().data(), sizeof(m_strDescription));
strncpy(m_strDescription, Project->GetFileName().toLatin1().data(), sizeof(m_strDescription) - 1);
m_strDescription[sizeof(m_strDescription) - 1] = 0;
}
@ -147,8 +149,6 @@ void PieceInfo::Load()
{
if (lcGetPiecesLibrary()->LoadPieceData(this))
mType = lcPieceInfoType::Part;
else
mBoundingBox = gPlaceholderMesh->mBoundingBox;
}
else
lcGetPiecesLibrary()->LoadPieceData(this);
@ -266,9 +266,6 @@ bool PieceInfo::BoxTest(const lcMatrix44& WorldMatrix, const lcVector4 WorldPlan
if (OutcodesOR == 0)
return true;
if (IsPlaceholder())
return gPlaceholderMesh->IntersectsPlanes(LocalPlanes);
if (mMesh && mMesh->IntersectsPlanes(LocalPlanes))
return true;
@ -305,10 +302,10 @@ void PieceInfo::AddRenderMesh(lcScene& Scene)
Scene.AddMesh(mMesh, lcMatrix44Identity(), gDefaultColor, lcRenderMeshState::Default);
}
void PieceInfo::AddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int ColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const
void PieceInfo::AddRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int ColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const
{
if (mMesh || IsPlaceholder())
Scene.AddMesh(IsPlaceholder() ? gPlaceholderMesh : mMesh, WorldMatrix, ColorIndex, RenderMeshState);
Scene->AddMesh(mMesh, WorldMatrix, ColorIndex, RenderMeshState);
if (IsModel())
mModel->AddSubModelRenderMeshes(Scene, WorldMatrix, ColorIndex, RenderMeshState, ParentActive);
@ -327,7 +324,7 @@ void PieceInfo::GetPartsList(int DefaultColorIndex, bool ScanSubModels, bool Add
if (ScanSubModels)
mModel->GetPartsList(DefaultColorIndex, ScanSubModels, AddSubModels, PartsList);
if (AddSubModels && DefaultColorIndex < gNumUserColors)
if (AddSubModels)
PartsList[this][DefaultColorIndex]++;
}
else if (IsProject())
@ -336,7 +333,7 @@ void PieceInfo::GetPartsList(int DefaultColorIndex, bool ScanSubModels, bool Add
if (Model)
Model->GetPartsList(DefaultColorIndex, ScanSubModels, AddSubModels, PartsList);
}
else if (DefaultColorIndex < gNumUserColors)
else
PartsList[this][DefaultColorIndex]++;
}
@ -383,6 +380,26 @@ void PieceInfo::CompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min
}
}
void PieceInfo::AddSubModelBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const
{
if (!IsModel())
{
lcVector3 BoxPoints[8];
if (!mMesh)
lcGetBoxCorners(GetBoundingBox(), BoxPoints);
else
lcGetBoxCorners(mMesh->mBoundingBox, BoxPoints);
for (int i = 0; i < 8; i++)
Points.emplace_back(lcMul31(BoxPoints[i], WorldMatrix));
}
else
{
mModel->SubModelAddBoundingBoxPoints(WorldMatrix, Points);
}
}
void PieceInfo::UpdateBoundingBox(std::vector<lcModel*>& UpdatedModels)
{
if (IsModel())

View file

@ -30,6 +30,7 @@ struct lcModelPartsEntry
};
class lcSynthInfo;
enum class lcZipFileType;
class PieceInfo
{
@ -117,7 +118,7 @@ public:
return mType != lcPieceInfoType::Part;
}
void SetZipFile(int ZipFileType, int ZipFileIndex)
void SetZipFile(lcZipFileType ZipFileType, int ZipFileIndex)
{
mZipFileType = ZipFileType;
mZipFileIndex = ZipFileIndex;
@ -130,6 +131,11 @@ public:
const char* Name = mFileName;
// Heuristic: Names matching '^[Uu]?[0-9]*[A-Za-z][^.][^.]' are patterned.
if (*Name == 'U' || *Name == 'u')
Name++;
while (*Name)
{
if (*Name < '0' || *Name > '9')
@ -138,7 +144,10 @@ public:
Name++;
}
if (*Name == 'P' || *Name == 'p')
if (!*Name || !((*Name >= 'A' && *Name <= 'Z') || (*Name >= 'a' && *Name <= 'z')))
return false;
if (Name[1] && Name[1] != '.' && Name[2] && Name[2] != '.')
return true;
return false;
@ -151,7 +160,7 @@ public:
void ZoomExtents(float FoV, float AspectRatio, lcMatrix44& ProjectionMatrix, lcMatrix44& ViewMatrix) const;
void AddRenderMesh(lcScene& Scene);
void AddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int ColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
void AddRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int ColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
void CreatePlaceholder(const char* Name);
@ -165,6 +174,7 @@ public:
void GetPartsList(int DefaultColorIndex, bool ScanSubModels, bool AddSubModels, lcPartsList& PartsList) const;
void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector<lcModelPartsEntry>& ModelParts) const;
void CompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const;
void AddSubModelBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const;
void UpdateBoundingBox(std::vector<lcModel*>& UpdatedModels);
void Load();
@ -173,7 +183,7 @@ public:
public:
char mFileName[LC_PIECE_NAME_LEN];
char m_strDescription[128];
int mZipFileType;
lcZipFileType mZipFileType;
int mZipFileIndex;
lcPieceInfoState mState;
int mFolderType;

View file

@ -5,9 +5,10 @@
#include "pieceinf.h"
#include "camera.h"
#include "project.h"
#include "lc_instructions.h"
#include "image.h"
#include "lc_mainwindow.h"
#include "view.h"
#include "lc_view.h"
#include "lc_library.h"
#include "lc_application.h"
#include "lc_profile.h"
@ -60,15 +61,17 @@ void lcHTMLExportOptions::SaveDefaults()
lcSetProfileInt(LC_PROFILE_HTML_IMAGE_HEIGHT, StepImagesHeight);
}
Project::Project()
Project::Project(bool IsPreview)
: mIsPreview(IsPreview)
{
mModified = false;
mActiveModel = new lcModel(tr("New Model.ldr"));
mActiveModel = new lcModel(tr(mIsPreview ? "Preview.ldr" : "New Model.ldr"), this, mIsPreview);
mActiveModel->CreatePieceInfo(this);
mActiveModel->SetSaved();
mModels.Add(mActiveModel);
QObject::connect(&mFileWatcher, SIGNAL(fileChanged(const QString&)), gMainWindow, SLOT(ProjectFileChanged(const QString&)));
if (!mIsPreview && gMainWindow)
QObject::connect(&mFileWatcher, SIGNAL(fileChanged(const QString&)), gMainWindow, SLOT(ProjectFileChanged(const QString&)));
}
Project::~Project()
@ -121,12 +124,8 @@ QString Project::GetImageFileName(bool AllowCurrentFolder) const
FileName = QLatin1String("image");
else
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QStringList cachePathList = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
FileName = cachePathList.first();
#else
FileName = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
#endif
QStringList CachePathList = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
FileName = CachePathList.first();
FileName = QDir(FileName).absoluteFilePath(QLatin1String("image"));
}
}
@ -149,8 +148,12 @@ void Project::SetActiveModel(int ModelIndex)
mModels[ModelIdx]->UpdatePieceInfo(UpdatedModels);
mActiveModel = mModels[ModelIndex];
gMainWindow->SetCurrentModelTab(mActiveModel);
mActiveModel->UpdateInterface();
if (!mIsPreview && gMainWindow)
{
gMainWindow->SetCurrentModelTab(mActiveModel);
mActiveModel->UpdateInterface();
}
}
void Project::SetActiveModel(const QString& FileName)
@ -245,7 +248,7 @@ lcModel* Project::CreateNewModel(bool ShowModel)
return nullptr;
mModified = true;
lcModel* Model = new lcModel(Name);
lcModel* Model = new lcModel(Name, this, false);
Model->CreatePieceInfo(this);
Model->SetSaved();
mModels.Add(Model);
@ -263,39 +266,53 @@ lcModel* Project::CreateNewModel(bool ShowModel)
void Project::ShowModelListDialog()
{
QList<QPair<QString, lcModel*>> Models;
#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
Models.reserve(mModels.GetSize());
#endif
lcQModelListDialog Dialog(gMainWindow, mModels);
for (int ModelIdx = 0; ModelIdx < mModels.GetSize(); ModelIdx++)
{
lcModel* Model = mModels[ModelIdx];
Models.append(QPair<QString, lcModel*>(Model->GetProperties().mFileName, Model));
}
lcQModelListDialog Dialog(gMainWindow, Models);
if (Dialog.exec() != QDialog::Accepted || Models.isEmpty())
if (Dialog.exec() != QDialog::Accepted)
return;
lcArray<lcModel*> NewModels;
std::vector<lcModelListDialogEntry> Results = Dialog.GetResults();
for (QList<QPair<QString, lcModel*>>::iterator it = Models.begin(); it != Models.end(); it++)
for (const lcModelListDialogEntry& Entry : Results)
{
lcModel* Model = it->second;
lcModel* Model = Entry.ExistingModel;
if (!Model)
{
Model = new lcModel(it->first);
const lcModel* Source = Entry.DuplicateSource;
if (!Source)
{
Model = new lcModel(Entry.Name, this, false);
}
else
{
Model = new lcModel(Source->GetProperties().mFileName, this, false);
QByteArray File;
QTextStream SaveStream(&File);
Source->SaveLDraw(SaveStream, false);
SaveStream.flush();
QBuffer Buffer(&File);
Buffer.open(QIODevice::ReadOnly);
Model->LoadLDraw(Buffer, this);
Model->SetFileName(Entry.Name);
Model->CreatePieceInfo(this);
}
Model->CreatePieceInfo(this);
Model->SetSaved();
mModified = true;
}
else if (Model->GetProperties().mFileName != it->first)
else if (Model->GetProperties().mFileName != Entry.Name)
{
Model->SetFileName(it->first);
lcGetPiecesLibrary()->RenamePiece(Model->GetPieceInfo(), it->first.toLatin1().constData());
Model->SetFileName(Entry.Name);
lcGetPiecesLibrary()->RenamePiece(Model->GetPieceInfo(), Entry.Name.toLatin1().constData());
for (lcModel* CheckModel : mModels)
CheckModel->RenamePiece(Model->GetPieceInfo());
@ -332,10 +349,10 @@ void Project::SetFileName(const QString& FileName)
if (mFileName == FileName)
return;
if (!mFileName.isEmpty())
if (!mIsPreview && !mFileName.isEmpty())
mFileWatcher.removePath(mFileName);
if (!FileName.isEmpty())
if (!mIsPreview && !FileName.isEmpty())
mFileWatcher.addPath(FileName);
mFileName = FileName;
@ -343,11 +360,15 @@ void Project::SetFileName(const QString& FileName)
bool Project::Load(const QString& FileName)
{
QWidget *parent = nullptr;
if (!mIsPreview)
parent = gMainWindow;
QFile File(FileName);
if (!File.open(QIODevice::ReadOnly))
{
QMessageBox::warning(gMainWindow, tr("Error"), tr("Error reading file '%1':\n%2").arg(FileName, File.errorString()));
QMessageBox::warning(parent, tr("Error"), tr("Error reading file '%1':\n%2").arg(FileName, File.errorString()));
return false;
}
@ -374,14 +395,24 @@ bool Project::Load(const QString& FileName)
while (!Buffer.atEnd())
{
lcModel* Model = new lcModel(QString());
lcModel* Model = new lcModel(QString(), this, mIsPreview);
int Pos = Model->SplitMPD(Buffer);
if (Models.empty() || !Model->GetFileName().isEmpty())
{
mModels.Add(Model);
Models.emplace_back(std::make_pair(Pos, Model));
Model->CreatePieceInfo(this);
auto ModelCompare = [Model](const std::pair<int, lcModel*>& ModelIt)
{
return ModelIt.second->GetFileName().compare(Model->GetFileName(), Qt::CaseInsensitive) == 0;
};
if (std::find_if(Models.begin(), Models.end(), ModelCompare) == Models.end())
{
mModels.Add(Model);
Models.emplace_back(std::make_pair(Pos, Model));
Model->CreatePieceInfo(this);
}
else
delete Model;
}
else
delete Model;
@ -401,7 +432,7 @@ bool Project::Load(const QString& FileName)
MemFile.WriteBuffer(FileData.constData(), FileData.size());
MemFile.Seek(0, SEEK_SET);
lcModel* Model = new lcModel(QString());
lcModel* Model = new lcModel(QString(), this, mIsPreview);
if (Model->LoadBinary(&MemFile))
{
@ -415,7 +446,7 @@ bool Project::Load(const QString& FileName)
if (mModels.IsEmpty())
{
QMessageBox::warning(gMainWindow, tr("Error"), tr("Error loading file '%1':\nFile format is not recognized.").arg(FileName));
QMessageBox::warning(parent, tr("Error"), tr("Error loading file '%1':\nFile format is not recognized.").arg(FileName));
return false;
}
@ -534,7 +565,7 @@ bool Project::ImportLDD(const QString& FileName)
mModels.DeleteAll();
QString ModelName = QFileInfo(FileName).completeBaseName();
lcModel* Model = new lcModel(ModelName);
lcModel* Model = new lcModel(ModelName, this, false);
if (Model->LoadLDD(QString::fromUtf8((const char*)XMLFile.mBuffer)))
{
@ -567,7 +598,7 @@ bool Project::ImportInventory(const QByteArray& Inventory, const QString& Name,
return false;
mModels.DeleteAll();
lcModel* Model = new lcModel(Name);
lcModel* Model = new lcModel(Name, this, false);
if (Model->LoadInventory(Inventory))
{
@ -655,27 +686,27 @@ QString Project::GetExportFileName(const QString& FileName, const QString& Defau
return QFileDialog::getSaveFileName(gMainWindow, DialogTitle, SaveFileName, DialogFilter);
}
void Project::Export3DStudio(const QString& FileName)
bool Project::Export3DStudio(const QString& FileName)
{
std::vector<lcModelPartsEntry> ModelParts = GetModelParts();
if (ModelParts.empty())
{
QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("Nothing to export."));
return;
return false;
}
QString SaveFileName = GetExportFileName(FileName, "3ds", tr("Export 3D Studio"), tr("3DS Files (*.3ds);;All Files (*.*)"));
if (SaveFileName.isEmpty())
return;
return false;
lcDiskFile File(SaveFileName);
if (!File.Open(QIODevice::WriteOnly))
{
QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Could not open file '%1' for writing.").arg(SaveFileName));
return;
return false;
}
long M3DStart = File.GetPosition();
@ -882,17 +913,15 @@ void Project::Export3DStudio(const QString& FileName)
File.WriteU16(0x0010); // CHK_COLOR_F
File.WriteU32(18);
File.WriteFloats(Properties.mBackgroundSolidColor, 3);
const lcPreferences& Preferences = lcGetPreferences();
lcVector3 BackgroundSolidColor = lcVector3FromColor(Preferences.mBackgroundSolidColor);
File.WriteFloats(BackgroundSolidColor, 3);
File.WriteU16(0x0013); // CHK_LIN_COLOR_F
File.WriteU32(18);
File.WriteFloats(Properties.mBackgroundSolidColor, 3);
File.WriteU16(0x1100); // CHK_BIT_MAP
QByteArray BackgroundImage = Properties.mBackgroundImage.toLatin1();
File.WriteU32(6 + 1 + (quint32)strlen(BackgroundImage.constData()));
File.WriteBuffer(BackgroundImage.constData(), strlen(BackgroundImage.constData()) + 1);
File.WriteFloats(BackgroundSolidColor, 3);
File.WriteU16(0x1300); // CHK_V_GRADIENT
File.WriteU32(118);
@ -902,43 +931,41 @@ void Project::Export3DStudio(const QString& FileName)
File.WriteU16(0x0010); // CHK_COLOR_F
File.WriteU32(18);
File.WriteFloats(Properties.mBackgroundGradientColor1, 3);
const lcVector3 BackgroundGradientColor1 = lcVector3FromColor(Preferences.mBackgroundGradientColorTop);
const lcVector3 BackgroundGradientColor2 = lcVector3FromColor(Preferences.mBackgroundGradientColorBottom);
File.WriteFloats(BackgroundGradientColor1, 3);
File.WriteU16(0x0013); // CHK_LIN_COLOR_F
File.WriteU32(18);
File.WriteFloats(Properties.mBackgroundGradientColor1, 3);
File.WriteFloats(BackgroundGradientColor1, 3);
File.WriteU16(0x0010); // CHK_COLOR_F
File.WriteU32(18);
File.WriteFloats((Properties.mBackgroundGradientColor1 + Properties.mBackgroundGradientColor2) / 2.0f, 3);
File.WriteFloats((BackgroundGradientColor1 + BackgroundGradientColor2) / 2.0f, 3);
File.WriteU16(0x0013); // CHK_LIN_COLOR_F
File.WriteU32(18);
File.WriteFloats((Properties.mBackgroundGradientColor1 + Properties.mBackgroundGradientColor2) / 2.0f, 3);
File.WriteFloats((BackgroundGradientColor1 + BackgroundGradientColor2) / 2.0f, 3);
File.WriteU16(0x0010); // CHK_COLOR_F
File.WriteU32(18);
File.WriteFloats(Properties.mBackgroundGradientColor2, 3);
File.WriteFloats(BackgroundGradientColor2, 3);
File.WriteU16(0x0013); // CHK_LIN_COLOR_F
File.WriteU32(18);
File.WriteFloats(Properties.mBackgroundGradientColor2, 3);
File.WriteFloats(BackgroundGradientColor2, 3);
if (Properties.mBackgroundType == LC_BACKGROUND_GRADIENT)
if (Preferences.mBackgroundGradient)
{
File.WriteU16(0x1301); // LIB3DS_USE_V_GRADIENT
File.WriteU32(6);
}
else if (Properties.mBackgroundType == LC_BACKGROUND_IMAGE)
{
File.WriteU16(0x1101); // LIB3DS_USE_BIT_MAP
File.WriteU32(6);
}
else
{
File.WriteU16(0x1201); // LIB3DS_USE_SOLID_BGND
@ -1096,6 +1123,8 @@ void Project::Export3DStudio(const QString& FileName)
File.Seek(M3DStart + 2, SEEK_SET);
File.WriteU32(M3DEnd - M3DStart);
File.Seek(M3DEnd, SEEK_SET);
return true;
}
void Project::ExportBrickLink()
@ -1162,27 +1191,27 @@ void Project::ExportBrickLink()
BrickLinkFile.WriteLine("</INVENTORY>\n");
}
void Project::ExportCOLLADA(const QString& FileName)
bool Project::ExportCOLLADA(const QString& FileName)
{
std::vector<lcModelPartsEntry> ModelParts = GetModelParts();
if (ModelParts.empty())
{
QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("Nothing to export."));
return;
return false;
}
QString SaveFileName = GetExportFileName(FileName, "dae", tr("Export COLLADA"), tr("COLLADA Files (*.dae);;All Files (*.*)"));
if (SaveFileName.isEmpty())
return;
return false;
QFile File(SaveFileName);
if (!File.open(QIODevice::WriteOnly))
{
QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Could not open file '%1' for writing.").arg(SaveFileName));
return;
return false;
}
QTextStream Stream(&File);
@ -1270,7 +1299,7 @@ void Project::ExportCOLLADA(const QString& FileName)
QString ID = GetMeshID(ModelPart);
if (!Mesh)
Mesh = gPlaceholderMesh;
continue;
Stream << QString("\t<geometry id=\"%1\">\r\n").arg(ID);
Stream << "\t\t<mesh>\r\n";
@ -1379,6 +1408,11 @@ void Project::ExportCOLLADA(const QString& FileName)
for (const lcModelPartsEntry& ModelPart : ModelParts)
{
lcMesh* Mesh = !ModelPart.Mesh ? ModelPart.Info->GetMesh() : ModelPart.Mesh;
if (!Mesh)
continue;
QString ID = GetMeshID(ModelPart);
Stream << "\t\t<node>\r\n";
@ -1395,11 +1429,6 @@ void Project::ExportCOLLADA(const QString& FileName)
Stream << "\t\t\t\t<bind_material>\r\n";
Stream << "\t\t\t\t\t<technique_common>\r\n";
lcMesh* Mesh = !ModelPart.Mesh ? ModelPart.Info->GetMesh() : ModelPart.Mesh;
if (!Mesh)
Mesh = gPlaceholderMesh;
for (int SectionIdx = 0; SectionIdx < Mesh->mLods[LC_MESH_LOD_HIGH].NumSections; SectionIdx++)
{
lcMeshSection* Section = &Mesh->mLods[LC_MESH_LOD_HIGH].Sections[SectionIdx];
@ -1430,6 +1459,8 @@ void Project::ExportCOLLADA(const QString& FileName)
Stream << "</scene>\r\n";
Stream << "</COLLADA>\r\n";
return true;
}
void Project::ExportCSV()
@ -1473,14 +1504,12 @@ void Project::ExportCSV()
}
}
std::vector<std::pair<lcModel*, lcStep>> Project::GetPageLayouts() const
lcInstructions* Project::GetInstructions()
{
std::vector<const lcModel*> AddedModels;
mInstructions.reset();
mInstructions = std::unique_ptr<lcInstructions>(new lcInstructions(this));
if (mActiveModel)
return mActiveModel->GetPageLayouts(AddedModels);
return std::vector<std::pair<lcModel*, lcStep>>();
return mInstructions.get();
}
void Project::ExportHTML(const lcHTMLExportOptions& Options)
@ -1504,7 +1533,7 @@ void Project::ExportHTML(const lcHTMLExportOptions& Options)
auto AddPartsListImage = [&Dir](QTextStream& Stream, lcModel* Model, lcStep Step, const QString& BaseName)
{
QImage Image = Model->GetPartsListImage(1024, Step);
QImage Image = Model->GetPartsListImage(1024, Step, LC_RGBA(255, 255, 255, 0), QFont("Arial", 16, QFont::Bold), Qt::black);
if (!Image.isNull())
{
@ -1731,7 +1760,7 @@ bool Project::ExportPOVRay(const QString& FileName)
char Line[1024];
lcPiecesLibrary* Library = lcGetPiecesLibrary();
std::map<const PieceInfo*, std::pair<char[LC_PIECE_NAME_LEN], int>> PieceTable;
std::map<const PieceInfo*, std::pair<char[LC_PIECE_NAME_LEN + 1], int>> PieceTable;
size_t NumColors = gColorList.size();
std::vector<std::array<char, LC_MAX_COLOR_NAME>> ColorTable(NumColors);
@ -1767,12 +1796,12 @@ bool Project::ExportPOVRay(const QString& FileName)
while (TableFile.ReadLine(Line, sizeof(Line)))
{
char Src[1024], Dst[1024], Flags[1024];
char Src[129], Dst[129], Flags[11];
if (*Line == ';')
continue;
if (sscanf(Line,"%s%s%s", Src, Dst, Flags) != 3)
if (sscanf(Line,"%128s%128s%10s", Src, Dst, Flags) != 3)
continue;
strcat(Src, ".dat");
@ -1783,21 +1812,21 @@ bool Project::ExportPOVRay(const QString& FileName)
if (strchr(Flags, 'L'))
{
std::pair<char[LC_PIECE_NAME_LEN], int>& Entry = PieceTable[Info];
std::pair<char[LC_PIECE_NAME_LEN + 1], int>& Entry = PieceTable[Info];
Entry.second |= LGEO_PIECE_LGEO;
sprintf(Entry.first, "lg_%s", Dst);
}
if (strchr(Flags, 'A'))
{
std::pair<char[LC_PIECE_NAME_LEN], int>& Entry = PieceTable[Info];
std::pair<char[LC_PIECE_NAME_LEN + 1], int>& Entry = PieceTable[Info];
Entry.second |= LGEO_PIECE_AR;
sprintf(Entry.first, "ar_%s", Dst);
}
if (strchr(Flags, 'S'))
{
std::pair<char[LC_PIECE_NAME_LEN], int>& Entry = PieceTable[Info];
std::pair<char[LC_PIECE_NAME_LEN + 1], int>& Entry = PieceTable[Info];
Entry.second |= LGEO_PIECE_SLOPE;
Entry.first[0] = 0;
}
@ -1853,7 +1882,7 @@ bool Project::ExportPOVRay(const QString& FileName)
if (!AddedMeshes.insert(Mesh).second)
continue;
const std::pair<char[LC_PIECE_NAME_LEN], int>& Entry = Search->second;
const std::pair<char[LC_PIECE_NAME_LEN + 1], int>& Entry = Search->second;
if (Entry.first[0])
{
sprintf(Line, "#include \"%s.inc\"\n", Entry.first);
@ -1892,7 +1921,7 @@ bool Project::ExportPOVRay(const QString& FileName)
for (size_t ColorIdx = 0; ColorIdx < NumColors; ColorIdx++)
ColorTablePointer[ColorIdx] = ColorTable[ColorIdx].data();
auto GetMeshName = [](const lcModelPartsEntry& ModelPart, char* Name)
auto GetMeshName = [](const lcModelPartsEntry& ModelPart, char (&Name)[LC_PIECE_NAME_LEN])
{
strcpy(Name, ModelPart.Info->mFileName);
@ -1904,7 +1933,8 @@ bool Project::ExportPOVRay(const QString& FileName)
{
char Suffix[32];
sprintf(Suffix, "_%p", ModelPart.Mesh);
strcat(Name, Suffix);
strncat(Name, Suffix, sizeof(Name) - 1);
Name[sizeof(Name) - 1] = 0;
}
};
@ -1923,8 +1953,10 @@ bool Project::ExportPOVRay(const QString& FileName)
if (!ModelPart.Mesh)
{
std::pair<char[LC_PIECE_NAME_LEN], int>& Entry = PieceTable[ModelPart.Info];
sprintf(Entry.first, "lc_%s", Name);
std::pair<char[LC_PIECE_NAME_LEN + 1], int>& Entry = PieceTable[ModelPart.Info];
strcpy(Entry.first, "lc_");
strncat(Entry.first, Name, sizeof(Entry.first) - 1);
Entry.first[sizeof(Entry.first) - 1] = 0;
}
Mesh->ExportPOVRay(POVFile, Name, &ColorTablePointer[0]);
@ -1933,16 +1965,16 @@ bool Project::ExportPOVRay(const QString& FileName)
POVFile.WriteLine(Line);
}
lcCamera* Camera = gMainWindow->GetActiveView()->mCamera;
const lcCamera* Camera = gMainWindow->GetActiveView()->GetCamera();
const lcVector3& Position = Camera->mPosition;
const lcVector3& Target = Camera->mTargetPosition;
const lcVector3& Up = Camera->mUpVector;
const lcModelProperties& Properties = mModels[0]->GetProperties();
sprintf(Line, "camera {\n perspective\n right x * image_width / image_height\n sky<%1g,%1g,%1g>\n location <%1g, %1g, %1g>\n look_at <%1g, %1g, %1g>\n angle %.0f * image_width / image_height\n}\n\n",
Up[1], Up[0], Up[2], Position[1] / 25.0f, Position[0] / 25.0f, Position[2] / 25.0f, Target[1] / 25.0f, Target[0] / 25.0f, Target[2] / 25.0f, Camera->m_fovy);
POVFile.WriteLine(Line);
sprintf(Line, "background { color rgb <%1g, %1g, %1g> }\n\n", Properties.mBackgroundSolidColor[0], Properties.mBackgroundSolidColor[1], Properties.mBackgroundSolidColor[2]);
lcVector3 BackgroundColor = lcVector3FromColor(lcGetPreferences().mBackgroundSolidColor);
sprintf(Line, "background { color rgb <%1g, %1g, %1g> }\n\n", BackgroundColor[0], BackgroundColor[1], BackgroundColor[2]);
POVFile.WriteLine(Line);
lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX);
@ -1984,7 +2016,7 @@ bool Project::ExportPOVRay(const QString& FileName)
if (!ModelPart.Mesh)
{
std::pair<char[LC_PIECE_NAME_LEN], int>& Entry = PieceTable[ModelPart.Info];
std::pair<char[LC_PIECE_NAME_LEN + 1], int>& Entry = PieceTable[ModelPart.Info];
if (Entry.second & LGEO_PIECE_SLOPE)
{
@ -2019,20 +2051,20 @@ bool Project::ExportPOVRay(const QString& FileName)
return true;
}
void Project::ExportWavefront(const QString& FileName)
bool Project::ExportWavefront(const QString& FileName)
{
std::vector<lcModelPartsEntry> ModelParts = GetModelParts();
if (ModelParts.empty())
{
QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("Nothing to export."));
return;
return false;
}
QString SaveFileName = GetExportFileName(FileName, QLatin1String("obj"), tr("Export Wavefront"), tr("Wavefront Files (*.obj);;All Files (*.*)"));
if (SaveFileName.isEmpty())
return;
return false;
lcDiskFile OBJFile(SaveFileName);
char Line[1024];
@ -2040,7 +2072,7 @@ void Project::ExportWavefront(const QString& FileName)
if (!OBJFile.Open(QIODevice::WriteOnly))
{
QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Could not open file '%1' for writing.").arg(SaveFileName));
return;
return false;
}
quint32 vert = 1;
@ -2057,7 +2089,7 @@ void Project::ExportWavefront(const QString& FileName)
if (!MaterialFile.Open(QIODevice::WriteOnly))
{
QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Could not open file '%1' for writing.").arg(MaterialFileName));
return;
return false;
}
MaterialFile.WriteLine("# Colors used by LeoCAD\n\n");
@ -2124,6 +2156,8 @@ void Project::ExportWavefront(const QString& FileName)
vert += Mesh->mNumVertices;
}
}
return true;
}
void Project::SaveImage()

View file

@ -1,6 +1,5 @@
#pragma once
#include "object.h"
#include "lc_array.h"
#include "lc_application.h"
@ -29,23 +28,14 @@ public:
bool PartsListEnd;
};
enum LC_MOUSE_TRACK
{
LC_TRACK_NONE,
LC_TRACK_LEFT,
LC_TRACK_RIGHT
};
class Project
{
public:
Project();
Project(bool IsPreview = false);
~Project();
Project(const Project&) = delete;
Project(Project&&) = delete;
Project& operator=(const Project&) = delete;
Project& operator=(Project&&) = delete;
const lcArray<lcModel*>& GetModels() const
{
@ -80,7 +70,7 @@ public:
QString GetImageFileName(bool AllowCurrentFolder) const;
std::vector<std::pair<lcModel*, lcStep>> GetPageLayouts() const;
lcInstructions* GetInstructions();
void SetActiveModel(int ModelIndex);
void SetActiveModel(const QString& FileName);
@ -98,13 +88,13 @@ public:
void SaveImage();
bool ExportModel(const QString& FileName, lcModel* Model) const;
void Export3DStudio(const QString& FileName);
bool Export3DStudio(const QString& FileName);
void ExportBrickLink();
void ExportCOLLADA(const QString& FileName);
bool ExportCOLLADA(const QString& FileName);
void ExportCSV();
void ExportHTML(const lcHTMLExportOptions& Options);
bool ExportPOVRay(const QString& FileName);
void ExportWavefront(const QString& FileName);
bool ExportWavefront(const QString& FileName);
void UpdatePieceInfo(PieceInfo* Info) const;
@ -113,12 +103,14 @@ protected:
std::vector<lcModelPartsEntry> GetModelParts();
void SetFileName(const QString& FileName);
bool mIsPreview;
bool mModified;
QString mFileName;
QFileSystemWatcher mFileWatcher;
lcArray<lcModel*> mModels;
lcModel* mActiveModel;
std::unique_ptr<lcInstructions> mInstructions;
Q_DECLARE_TR_FUNCTIONS(Project);
};

View file

@ -93,16 +93,13 @@ TexFont gTexFont;
TexFont::TexFont()
{
mRefCount = 0;
mTexture = 0;
memset(&mGlyphs, 0, sizeof(mGlyphs));
}
bool TexFont::Load(lcContext* Context)
bool TexFont::Initialize(lcContext* Context)
{
mRefCount++;
if (mRefCount != 1)
if (mTexture)
return true;
mFontHeight = 16;
@ -151,14 +148,9 @@ bool TexFont::Load(lcContext* Context)
return true;
}
void TexFont::Release()
void TexFont::Reset()
{
mRefCount--;
if (mRefCount == 0)
{
glDeleteTextures(1, &mTexture);
mTexture = 0;
}
mTexture = 0;
}
void TexFont::GetStringDimensions(int* cx, int* cy, const char* Text) const

View file

@ -15,8 +15,8 @@ public:
return mTexture;
}
bool Load(lcContext* Context);
void Release();
bool Initialize(lcContext* Context);
void Reset();
void PrintText(lcContext* Context, float Left, float Top, float Z, const char* Text) const;
void GetTriangles(const lcMatrix44& Transform, const char* Text, float* Buffer) const;
@ -34,7 +34,6 @@ protected:
int mTextureWidth;
int mTextureHeight;
int mFontHeight;
int mRefCount;
};
extern TexFont gTexFont;

View file

@ -1,211 +0,0 @@
#pragma once
#include "lc_glwidget.h"
#include "camera.h"
#include "lc_scene.h"
#include "lc_viewsphere.h"
#include "lc_commands.h"
enum class lcTrackButton
{
None,
Left,
Middle,
Right
};
enum lcTrackTool
{
LC_TRACKTOOL_NONE,
LC_TRACKTOOL_INSERT,
LC_TRACKTOOL_POINTLIGHT,
LC_TRACKTOOL_SPOTLIGHT,
LC_TRACKTOOL_CAMERA,
LC_TRACKTOOL_SELECT,
LC_TRACKTOOL_MOVE_X,
LC_TRACKTOOL_MOVE_Y,
LC_TRACKTOOL_MOVE_Z,
LC_TRACKTOOL_MOVE_XY,
LC_TRACKTOOL_MOVE_XZ,
LC_TRACKTOOL_MOVE_YZ,
LC_TRACKTOOL_MOVE_XYZ,
LC_TRACKTOOL_ROTATE_X,
LC_TRACKTOOL_ROTATE_Y,
LC_TRACKTOOL_ROTATE_Z,
LC_TRACKTOOL_ROTATE_XY,
LC_TRACKTOOL_ROTATE_XYZ,
LC_TRACKTOOL_SCALE_PLUS,
LC_TRACKTOOL_SCALE_MINUS,
LC_TRACKTOOL_ERASER,
LC_TRACKTOOL_PAINT,
LC_TRACKTOOL_COLOR_PICKER,
LC_TRACKTOOL_ZOOM,
LC_TRACKTOOL_PAN,
LC_TRACKTOOL_ORBIT_X,
LC_TRACKTOOL_ORBIT_Y,
LC_TRACKTOOL_ORBIT_XY,
LC_TRACKTOOL_ROLL,
LC_TRACKTOOL_ZOOM_REGION,
LC_TRACKTOOL_COUNT
};
enum class lcDragState
{
None,
Piece,
Color
};
class View : public lcGLWidget
{
public:
View(lcModel* Model);
~View();
View(const View&) = delete;
View(View&&) = delete;
View& operator=(const View&) = delete;
View& operator=(View&&) = delete;
void Clear()
{
mModel = nullptr;
mActiveSubmodelInstance = nullptr;
}
lcModel* GetModel() const
{
return mModel;
}
lcModel* GetActiveModel() const;
void SetTopSubmodelActive();
void SetSelectedSubmodelActive();
static void CreateResources(lcContext* Context);
static void DestroyResources(lcContext* Context);
void OnDraw() override;
void OnInitialUpdate() override;
void OnUpdateCursor() override;
void OnLeftButtonDown() override;
void OnLeftButtonUp() override;
void OnLeftButtonDoubleClick() override;
void OnMiddleButtonDown() override;
void OnMiddleButtonUp() override;
void OnRightButtonDown() override;
void OnRightButtonUp() override;
void OnBackButtonUp() override;
void OnForwardButtonUp() override;
void OnMouseMove() override;
void OnMouseWheel(float Direction) override;
bool IsTracking() const
{
return mTrackButton != lcTrackButton::None;
}
void StartOrbitTracking();
void CancelTrackingOrClearSelection();
void BeginDrag(lcDragState DragState);
void EndDrag(bool Accept);
void SetProjection(bool Ortho);
void LookAt();
void ZoomExtents();
void MoveCamera(const lcVector3& Direction);
void Zoom(float Amount);
void RemoveCamera();
void SetCamera(lcCamera* Camera, bool ForceCopy);
void SetCamera(const char* CameraName);
void SetCameraIndex(int Index);
void SetViewpoint(lcViewpoint Viewpoint);
void SetViewpoint(const lcVector3& Position);
void SetCameraAngles(float Latitude, float Longitude);
void SetDefaultCamera();
lcMatrix44 GetProjectionMatrix() const;
lcCursor GetCursor() const;
void ShowContextMenu() const;
lcVector3 GetMoveDirection(const lcVector3& Direction) const;
lcMatrix44 GetPieceInsertPosition(bool IgnoreSelected, PieceInfo* Info) const;
lcVector3 GetCameraLightInsertPosition() const;
void GetRayUnderPointer(lcVector3& Start, lcVector3& End) const;
lcObjectSection FindObjectUnderPointer(bool PiecesOnly, bool IgnoreSelected) const;
lcArray<lcObject*> FindObjectsInBox(float x1, float y1, float x2, float y2) const;
lcCamera* mCamera;
lcVector3 ProjectPoint(const lcVector3& Point) const
{
int Viewport[4] = { 0, 0, mWidth, mHeight };
return lcProjectPoint(Point, mCamera->mWorldView, GetProjectionMatrix(), Viewport);
}
lcVector3 UnprojectPoint(const lcVector3& Point) const
{
int Viewport[4] = { 0, 0, mWidth, mHeight };
return lcUnprojectPoint(Point, mCamera->mWorldView, GetProjectionMatrix(), Viewport);
}
void UnprojectPoints(lcVector3* Points, int NumPoints) const
{
int Viewport[4] = { 0, 0, mWidth, mHeight };
lcUnprojectPoints(Points, NumPoints, mCamera->mWorldView, GetProjectionMatrix(), Viewport);
}
bool BeginRenderToImage(int Width, int Height);
void EndRenderToImage();
QImage GetRenderImage() const
{
return mRenderImage;
}
protected:
static void CreateSelectMoveOverlayMesh(lcContext* Context);
void DrawSelectMoveOverlay();
void DrawRotateOverlay();
void DrawSelectZoomRegionOverlay();
void DrawRotateViewOverlay();
void DrawGrid();
void DrawAxes();
void DrawViewport();
void UpdateTrackTool();
bool IsTrackToolAllowed(lcTrackTool TrackTool, quint32 AllowedTransforms) const;
lcTool GetCurrentTool() const;
lcTrackTool GetOverrideTrackTool(Qt::MouseButton Button) const;
float GetOverlayScale() const;
void StartTracking(lcTrackButton TrackButton);
void StopTracking(bool Accept);
void OnButtonDown(lcTrackButton TrackButton);
lcMatrix44 GetTileProjectionMatrix(int CurrentRow, int CurrentColumn, int CurrentTileWidth, int CurrentTileHeight) const;
lcModel* mModel;
lcPiece* mActiveSubmodelInstance;
lcMatrix44 mActiveSubmodelTransform;
lcScene mScene;
lcDragState mDragState;
lcTrackButton mTrackButton;
lcTrackTool mTrackTool;
bool mTrackToolFromOverlay;
bool mTrackUpdated;
int mMouseDownX;
int mMouseDownY;
lcVector3 mMouseDownPosition;
PieceInfo* mMouseDownPiece;
QImage mRenderImage;
std::pair<lcFramebuffer, lcFramebuffer> mRenderFramebuffer;
lcViewSphere mViewSphere;
lcVertexBuffer mGridBuffer;
int mGridSettings[7];
static lcVertexBuffer mRotateMoveVertexBuffer;
static lcIndexBuffer mRotateMoveIndexBuffer;
};

View file

@ -18,25 +18,40 @@ rendering.
- LeoCAD for Windows:
Download LeoCAD-Windows-19.07.exe to your computer, double click on the
icon to launch the installer and follow the intructions.
Download the latest LeoCAD-Windows.exe to your computer, double click on
the icon to launch the installer and follow the instructions.
- LeoCAD for Linux:
Download LeoCAD-Linux-19.07-x86_64.AppImage, make the file executable
There are multiple ways to install LeoCAD on Linux.
* AppImage:
Download the latest LeoCAD-Linux.AppImage, make the file executable
(chmod +x) and run it.
* Flatpak:
You can also install LeoCAD releases as a Flatpak from Flathub:
https://flathub.org/apps/details/org.leocad.LeoCAD
Note: there might be a delay for new releases to appear there. If
you have it already installed, it will be updated.
* From source:
If you prefer to compile LeoCAD yourself, go to the GitHub releases page
at https://github.com/leozide/leocad/releases/latest and download the
at https://github.com/leozide/leocad/releases/latest and download the
source archive from there. If you do not already have a Parts Library
installed, you will need to download one and follow the installation
instructions. More information on how to compile your own executable is
available in the Documentation section of https://www.leocad.org
- LeoCAD for Mac OSX:
- LeoCAD for macOS:
Download LeoCAD-macOS-19.07.dmg to your computer, double click on the
icon to open the archive and copy LeoCAD.app to your Applications folder.
Download the latest LeoCAD-macOS.dmg to your computer, double click on
the icon to open the archive, copy LeoCAD.app to your Applications folder
and then launch it from there.
New users should read the online tutorial located at
https://www.leocad.org/docs/tutorial1.html to learn how to use LeoCAD.
@ -51,6 +66,9 @@ Online Resources
- GitHub page:
https://github.com/leozide/leocad
- Unstable builds:
https://github.com/leozide/leocad/releases/tag/continuous
Legal Disclaimer
----------------

View file

@ -1,10 +1,10 @@
.TH LEOCAD 1 "20 July 2000"
.TH LEOCAD 1 "26 January 2021"
.\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection
.\" other parms are allowed: see man(7), man(1)
.\" other params are allowed: see man(7), man(1)
.SH NAME
LeoCAD \- CAD program for LEGO models.
.SH SYNOPSIS
\fIleocad \fR[\fI infile \fR[ \-i \fR[\fI outfile.ext \fR]\fI \fR[\fI\-w x\fR]\fI \fR[\fI\-h y\fR] ] \fR] [\fI\-l path\fR]
\fIleocad \fR[\fIOPTIONS\fR] [\fIINFILE\fR]
.SH "DESCRIPTION"
\fILeoCAD \fR is a CAD program for creating virtual LEGO models. It
has an easy to use interface and includes thousands of different
@ -12,20 +12,23 @@ parts in its library.
.SH OPTIONS
Below is a summary of all of the options that \fILeoCAD\fR
accepts. Most options have two equivalent names, one of
accepts. Many options have two equivalent names, one of
which is a single letter preceded by -, and the other of
which is a long name preceded by --. Brackets ([ and ])
indicate that an option takes an optional argument.
indicate that an option takes an optional parameter.
.TP
.B infile
Loads the project file \fIinfile\fR
.TP
.BI "\-i [" outfile.ext ]
.ns
\fB\-l \fIpath\fR, \fB\-\-libpath \fIpath
.br
Set the parts library location.
.TP
.BI "\-\-image [" outfile.ext ]
\fB\-i \fR[\fIoutfile.ext\fR], \fB\-\-image \fR[\fIoutfile.ext\fR]
.br
Saves a picture to \fIoutfile.ext \fR in the image format specified
by \fIext\fR and exits. If outfile is not given then the program will
use a name based on \fIinfile\fR. The file format is selected by \fIext\fR
@ -33,83 +36,169 @@ and can be gif, bmp, png or jpg (if \fIext\fR is not present then the
default preferences format will be used).
.TP
.BI "\-w "width
.ns
.TP
.BI "\-\-width "width
\fB\-w \fIwidth\fR, \fB\-\-width \fIwidth
.br
Sets the width of the picture to \fIwidth\fR.
.TP
.BI "\-h "height
.ns
.TP
.BI "\-\-height "height
\fB\-h \fIheight\fR, \fB\-\-height \fIheight
.br
Sets the height of the picture to \fIheight\fR.
.TP
.BI "\-f "time
.ns
.TP
.BI "\-\-from "time
Start saving pictures at the step \fItime\fR.
\fB\-f \fItime\fR, \fB\-\-from \fItime
.br
Start saving pictures at the step \fItime\fR. Steps start at 1.
.TP
.BI "\-t "time
.ns
.TP
.BI "\-\-to "time
\fB\-t \fItime\fR, \fB\-\-to \fItime
.br
Save pictures until the step \fItime\fR.
.TP
.BI "\-m "model
.ns
.TP
.BI "\-\-model "model
Sets the active submodel to \fImodel\fR.
\fB\-s \fIsubmodel\fR, \fB\-\-submodel \fIsubmodel
.br
Sets the active submodel to \fIsubmodel\fR.
.TP
.BI "\-c "camera
.ns
.TP
.BI "\-\-camera "camera
\fB\-c \fIcamera\fR, \fB\-\-camera \fIcamera
.br
Sets the active camera to \fIcamera\fR.
.TP
.BI "\-\-viewpoint "front\ back\ left\ right\ top\ bottom\ home
Sets the viewpoint to one of the predefined angles.
\fB\-ss \fIid\fR,\ \fB\-\-stud\-style\ \fIid
.br
Set the stud style. Valid values 0=Plain, 1=Thin Lines Logo, 2=Outline Logo, 3=Sharp Top Logo, 4=Rounded Top Logo, 5=Flattened Logo, 6=High Contrast, 7=High Contrast with Logo.
.TP
\fB\-\-viewpoint \fRfront\ |\ back\ |\ left\ |\ right\ |\ top\ |\ bottom\ |\ home
.br
Sets the viewpoint to one of the predefined view angles.
.TP
.BI "\-\-camera\-angles " latitude " " longitude
Set the camera angles in degrees around the model.
.TP
.BI "\-\-camera\-position " x " " y " " z " " tx " " ty " " tz " " ux " " uy " " uz
Set the camera position, target and up vector using the \fILeoCAD\fR coordinate system.
.TP
.BI "\-\-camera\-position-ldraw " x " " y " " z " " tx " " ty " " tz " " ux " " uy " " uz
Set the camera position, target and up vector using the \fILDraw\fR coordinate system.
.TP
.B \-\-orthographic
Use an orthographic projection.
.TP
.BI "\-\-fov " degrees
Set the vertical field of view used to render images.
.TP
.BI "\-\-zplanes " near " " far
Set the near and far clipping planes used to render images (1 <= \fInear\fR < \fIfar\fR).
.TP
.B \-\-fade\-steps
Render parts from prior steps faded.
.TP
.B \-\-no\-fade\-steps
Do not render parts from prior steps faded.
.TP
.BI "\-\-fade\-steps\-color " color
Color to use for rendering faded parts. (#AARRGGBB where AA, RR, GG, and BB are hexadecimal values for alpha, red, green, and blue respectively.)
.TP
.B \-\-highlight
Adds a border around the pieces in the step they appear when saving pictures.
Highlight parts in the steps they appear.
.TP
.BI "\-l "path
.ns
.TP
.BI "\-\-libpath "path
Use alternate parts library found in \fIpath \fR. The Linux version
of \fILeoCAD \fRuses /usr/share/leocad/ as the default.
.B \-\-no\-highlight
Do not highlight parts in the steps they appear.
.TP
.BI "\-obj [" outfile.obj ]
.BI "\-\-highlight\-color " color
Color to use to highlight parts, (#AARRGGBB where AA, RR, GG, and BB are hexadecimal values for alpha, red, green, and blue respectively.)
.TP
\fB\-\-shading \fRwireframe\ |\ flat\ |\ default\ |\ full
.br
Select shading mode for rendering.
.TP
.BI "\-\-line-width " width
Set the with of the edge lines.
.TP
.BI "\-\-aa\-samples " count
AntiAliasing sample size (1, 2, 4, or 8).
.TP
\fB\-scc \fI#AARRGGBB\fR,\ \fB\-\-stud\-cylinder\-color\ \fI#AARRGGBB
.br
High contrast stud cylinder color.
.TP
\fB\-ec \fI#AARRGGBB\fR,\ \fB\-\-edge\-color\ \fI#AARRGGBB
.br
High contrast edge color.
.TP
\fB\-bec \fI#AARRGGBB\fR,\ \fB\-\-black\-edge\-color\ \fI#AARRGGBB
.br
High contrast edge color for black parts.
.TP
\fB\-dec \fI#AARRGGBB\fR,\ \fB\-\-dark\-edge\-color\ \fI#AARRGGBB
.br
High contrast edge color for dark color parts.
.TP
\fB\-aec,\ \fB\-\-automate\-edge\-color
.br
Enable automatically adjusted edge colors.\
.TP
\fB\-cc \fIfloat\fR,\ \fB\-\-color\-contrast\ \ffloat
.br
Set the near and far clipping planes used to render images (1 <= \fInear\fR < \fIfar\fR).
.TP
\fB\-ldv \fIfloat\fR,\ \fB\-\-light\-dark\-value\ \ffloat
.br
Set the value to indicate a light or dark color.
.TP
\fB\-obj \fR[\fIoutfile.obj\fR]
.br
Exports the model to wavefront format.
.TP
.BI "\-3ds [" outfile.3ds ]
\fB\-3ds \fR[\fIoutfile.3ds\fR]
.br
Exports the model to 3DS format.
.TP
.BI "\-dae [" outfile.dae ]
\fB\-dae \fR[\fIoutfile.dae\fR]
.br
Exports the model to COLLADA DAE format.
.TP
.BI "\-html [" path ]
\fB\-html \fR[\fIpath\fR]
.br
Creates an HTML page for the model.
.TP
.BR \-v ",\ " \-\-version
Output version information and exit.
.TP
.BR \-? ",\ " \-\-help
Display a brief usage synopsis and exit.
.SH ENVIRONMENT
``LEOCAD_LIB'' may be set to the path of the parts library.
@ -132,6 +221,6 @@ If you find any bugs please report them at https://github.com/leozide/leocad/iss
\fILeoCAD \fRis written by Leonardo Zide <leozide@gmail.com>.
You can visit the LeoCAD homepage at https://www.leocad.org/
This manual page was written by Patrick Mahoney <pat7@gmx.net>,
This manual page was originally written by Patrick Mahoney <pat7@gmx.net>,
for the Debian GNU/Linux system (but may be used by others).
It has since been edited by others.

View file

@ -1,16 +1,18 @@
QT += core gui opengl network xml
QT += core gui opengl network xml concurrent
QT *= printsupport
TEMPLATE = app
greaterThan(QT_MAJOR_VERSION, 4) {
QT *= printsupport
QT += concurrent
lessThan(QT_MAJOR_VERSION, 5) {
error("LeoCAD requires Qt5.4 or later.")
}
equals(QT_MAJOR_VERSION, 5) {
qtHaveModule(gamepad) {
QT += gamepad
DEFINES += LC_ENABLE_GAMEPAD
}
equals(QT_MAJOR_VERSION, 5):lessThan(QT_MINOR_VERSION, 4) {
error("LeoCAD requires Qt5.4 or later.")
}
qtHaveModule(gamepad) {
QT += gamepad
DEFINES += LC_ENABLE_GAMEPAD
}
INCLUDEPATH += qt common
@ -18,7 +20,7 @@ CONFIG += precompile_header incremental c++11 force_debug_info
win32 {
RC_ICONS = resources/leocad.ico
VERSION = 19.7.1.0
VERSION = 21.1.0.0
QMAKE_TARGET_COMPANY = LeoCAD Software
QMAKE_TARGET_DESCRIPTION = LeoCAD
QMAKE_TARGET_COPYRIGHT = "Copyright (C) LeoCAD.org"
@ -29,17 +31,13 @@ win32 {
LIBS += -lwininet
}
win32-msvc* {
QMAKE_CXXFLAGS_WARN_ON += -wd4100
QMAKE_CXXFLAGS *= /MP /W4
QMAKE_CXXFLAGS_WARN_ON += /W4 -wd4100
QMAKE_CXXFLAGS *= /MP
PRECOMPILED_HEADER = common/lc_global.h
DEFINES += _CRT_SECURE_NO_WARNINGS _CRT_SECURE_NO_DEPRECATE=1 _CRT_NONSTDC_NO_WARNINGS=1
greaterThan(QT_MAJOR_VERSION, 4) {
INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QtZlib
} else {
INCLUDEPATH += $$[QT_INSTALL_PREFIX]/src/3rdparty/zlib
}
QMAKE_LFLAGS += /INCREMENTAL
PRECOMPILED_SOURCE = common/lc_global.cpp
DEFINES += _CRT_SECURE_NO_WARNINGS _CRT_SECURE_NO_DEPRECATE=1 _CRT_NONSTDC_NO_WARNINGS=1
INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QtZlib
QMAKE_LFLAGS += /INCREMENTAL
LIBS += -ladvapi32 -lshell32 -lopengl32 -luser32
} else {
PRECOMPILED_HEADER = common/lc_global.h
@ -47,17 +45,6 @@ win32-msvc* {
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter
}
lessThan(QT_MAJOR_VERSION, 5) {
unix {
GCC_VERSION = $$system(g++ -dumpversion)
greaterThan(GCC_VERSION, 4.6) {
QMAKE_CXXFLAGS += -std=c++11
} else {
QMAKE_CXXFLAGS += -std=c++0x
}
}
}
isEmpty(QMAKE_LRELEASE) {
win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]\\lrelease.exe
else:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease
@ -116,11 +103,10 @@ unix:!macx {
isEmpty(INSTALL_PREFIX):INSTALL_PREFIX = /usr
isEmpty(BIN_DIR):BIN_DIR = $$INSTALL_PREFIX/bin
isEmpty(DOCS_DIR):DOCS_DIR = $$INSTALL_PREFIX/share/doc/leocad
isEmpty(ICON_DIR):ICON_DIR = $$INSTALL_PREFIX/share/pixmaps
isEmpty(ICON_DIR):ICON_DIR = $$INSTALL_PREFIX/share/icons
isEmpty(MAN_DIR):MAN_DIR = $$INSTALL_PREFIX/share/man/man1
isEmpty(DESKTOP_DIR):DESKTOP_DIR = $$INSTALL_PREFIX/share/applications
isEmpty(MIME_DIR):MIME_DIR = $$INSTALL_PREFIX/share/mime/packages
isEmpty(MIME_ICON_DIR):MIME_ICON_DIR = $$INSTALL_PREFIX/share/icons/hicolor/scalable/mimetypes
isEmpty(APPDATA_DIR):APPDATA_DIR = $$INSTALL_PREFIX/share/metainfo
target.path = $$BIN_DIR
@ -130,16 +116,22 @@ unix:!macx {
man.files = docs/leocad.1
desktop.path = $$DESKTOP_DIR
desktop.files = qt/leocad.desktop
icon.path = $$ICON_DIR
icon.files = resources/leocad.png
icons.path = $$ICON_DIR/hicolor
icons.files += tools/icon/128x128
icons.files += tools/icon/16x16
icons.files += tools/icon/24x24
icons.files += tools/icon/256x256
icons.files += tools/icon/32x32
icons.files += tools/icon/48x48
icons.files += tools/icon/512x512
icons.files += tools/icon/64x64
icons.files += tools/icon/scalable
mime.path = $$MIME_DIR
mime.files = qt/leocad.xml
mime_icon.path = $$MIME_ICON_DIR
mime_icon.files = resources/application-vnd.leocad.svg
appdata.path = $$APPDATA_DIR
appdata.files = tools/setup/leocad.appdata.xml
INSTALLS += target docs man desktop icon mime mime_icon appdata
INSTALLS += target docs man desktop icons mime appdata
!isEmpty(DISABLE_UPDATE_CHECK) {
DEFINES += LC_DISABLE_UPDATE_CHECK=$$DISABLE_UPDATE_CHECK
@ -158,159 +150,167 @@ macx {
document_icon.path = Contents/Resources
library.files += $$_PRO_FILE_PWD_/library.bin
library.path = Contents/Resources
povray.files += $$_PRO_FILE_PWD_/tools/povray/povray
povray.files += $$_PRO_FILE_PWD_/povray
povray.path = Contents/MacOS
QMAKE_BUNDLE_DATA += document_icon library povray
DEFINES += LC_DISABLE_UPDATE_CHECK=1
}
SOURCES += common/view.cpp \
common/texfont.cpp \
common/project.cpp \
common/pieceinf.cpp \
common/piece.cpp \
common/object.cpp \
common/minifig.cpp \
common/light.cpp \
common/lc_application.cpp \
common/lc_category.cpp \
common/lc_colors.cpp \
common/lc_commands.cpp \
common/lc_context.cpp \
common/lc_file.cpp \
common/lc_glextensions.cpp \
common/lc_http.cpp \
common/lc_library.cpp \
common/lc_lxf.cpp \
common/lc_mainwindow.cpp \
common/lc_mesh.cpp \
common/lc_meshloader.cpp \
common/lc_model.cpp \
common/lc_profile.cpp \
common/lc_scene.cpp \
common/lc_selectbycolordialog.cpp \
common/lc_shortcuts.cpp \
common/lc_stringcache.cpp \
common/lc_synth.cpp \
common/lc_texture.cpp \
common/lc_viewsphere.cpp \
common/lc_zipfile.cpp \
common/image.cpp \
common/group.cpp \
common/camera.cpp \
qt/system.cpp \
qt/qtmain.cpp \
qt/lc_qarraydialog.cpp \
qt/lc_qgroupdialog.cpp \
qt/lc_qaboutdialog.cpp \
qt/lc_qeditgroupsdialog.cpp \
qt/lc_qselectdialog.cpp \
qt/lc_qpropertiesdialog.cpp \
qt/lc_qhtmldialog.cpp \
qt/lc_qminifigdialog.cpp \
qt/lc_qpreferencesdialog.cpp \
qt/lc_qcategorydialog.cpp \
qt/lc_qimagedialog.cpp \
qt/lc_qupdatedialog.cpp \
qt/lc_qutils.cpp \
qt/lc_qpropertiestree.cpp \
qt/lc_qcolorpicker.cpp \
qt/lc_qglwidget.cpp \
qt/lc_qcolorlist.cpp \
qt/lc_qfinddialog.cpp \
qt/lc_qmodellistdialog.cpp \
common/lc_partselectionwidget.cpp \
common/lc_timelinewidget.cpp \
qt/lc_renderdialog.cpp \
qt/lc_setsdatabasedialog.cpp \
common/lc_partpalettedialog.cpp
SOURCES += \
common/texfont.cpp \
common/project.cpp \
common/pieceinf.cpp \
common/piece.cpp \
common/object.cpp \
common/minifig.cpp \
common/light.cpp \
common/lc_application.cpp \
common/lc_category.cpp \
common/lc_collapsiblewidget.cpp \
common/lc_colors.cpp \
common/lc_commands.cpp \
common/lc_context.cpp \
common/lc_edgecolordialog.cpp \
common/lc_file.cpp \
common/lc_findreplacewidget.cpp \
common/lc_glextensions.cpp \
common/lc_http.cpp \
common/lc_instructions.cpp \
common/lc_instructionsdialog.cpp \
common/lc_library.cpp \
common/lc_lxf.cpp \
common/lc_mainwindow.cpp \
common/lc_mesh.cpp \
common/lc_meshloader.cpp \
common/lc_minifigdialog.cpp \
common/lc_model.cpp \
common/lc_pagesetupdialog.cpp \
common/lc_partselectionwidget.cpp \
common/lc_previewwidget.cpp \
common/lc_profile.cpp \
common/lc_scene.cpp \
common/lc_shortcuts.cpp \
common/lc_stringcache.cpp \
common/lc_synth.cpp \
common/lc_texture.cpp \
common/lc_timelinewidget.cpp \
common/lc_view.cpp \
common/lc_viewsphere.cpp \
common/lc_viewwidget.cpp \
common/lc_zipfile.cpp \
common/image.cpp \
common/group.cpp \
common/camera.cpp \
qt/system.cpp \
qt/qtmain.cpp \
qt/lc_qarraydialog.cpp \
qt/lc_qgroupdialog.cpp \
qt/lc_qaboutdialog.cpp \
qt/lc_qeditgroupsdialog.cpp \
qt/lc_qselectdialog.cpp \
qt/lc_qpropertiesdialog.cpp \
qt/lc_qhtmldialog.cpp \
qt/lc_qpreferencesdialog.cpp \
qt/lc_qcategorydialog.cpp \
qt/lc_qimagedialog.cpp \
qt/lc_qupdatedialog.cpp \
qt/lc_qutils.cpp \
qt/lc_qpropertiestree.cpp \
qt/lc_qcolorpicker.cpp \
qt/lc_qcolorlist.cpp \
qt/lc_qmodellistdialog.cpp \
qt/lc_renderdialog.cpp \
qt/lc_setsdatabasedialog.cpp \
common/lc_partpalettedialog.cpp
HEADERS += \
common/view.h \
common/texfont.h \
common/project.h \
common/pieceinf.h \
common/piece.h \
common/object.h \
common/minifig.h \
common/light.h \
common/lc_application.h \
common/lc_array.h \
common/lc_basewindow.h \
common/lc_category.h \
common/lc_colors.h \
common/lc_commands.h \
common/lc_context.h \
common/lc_file.h \
common/lc_glext.h \
common/lc_glextensions.h \
common/lc_global.h \
common/lc_glwidget.h \
common/lc_http.h \
common/lc_library.h \
common/lc_lxf.h \
common/lc_mainwindow.h \
common/lc_math.h \
common/lc_mesh.h \
common/lc_meshloader.h \
common/lc_model.h \
common/lc_profile.h \
common/lc_scene.h \
common/lc_selectbycolordialog.h \
common/lc_shortcuts.h \
common/lc_stringcache.h \
common/lc_synth.h \
common/lc_texture.h \
common/lc_viewsphere.h \
common/lc_zipfile.h \
common/image.h \
common/group.h \
common/camera.h \
qt/lc_qarraydialog.h \
qt/lc_qgroupdialog.h \
qt/lc_qaboutdialog.h \
qt/lc_qeditgroupsdialog.h \
qt/lc_qselectdialog.h \
qt/lc_qpropertiesdialog.h \
qt/lc_qhtmldialog.h \
qt/lc_qminifigdialog.h \
qt/lc_qpreferencesdialog.h \
qt/lc_qcategorydialog.h \
qt/lc_qimagedialog.h \
qt/lc_qupdatedialog.h \
qt/lc_qutils.h \
qt/lc_qpropertiestree.h \
qt/lc_qcolorpicker.h \
qt/lc_qglwidget.h \
qt/lc_qcolorlist.h \
qt/lc_qfinddialog.h \
qt/lc_qmodellistdialog.h \
common/lc_partselectionwidget.h \
common/lc_timelinewidget.h \
qt/lc_renderdialog.h \
qt/lc_setsdatabasedialog.h \
common/lc_partpalettedialog.h
FORMS += \
qt/lc_qarraydialog.ui \
qt/lc_qgroupdialog.ui \
qt/lc_qaboutdialog.ui \
qt/lc_qeditgroupsdialog.ui \
qt/lc_qselectdialog.ui \
qt/lc_qpropertiesdialog.ui \
qt/lc_qhtmldialog.ui \
qt/lc_qminifigdialog.ui \
qt/lc_qpreferencesdialog.ui \
qt/lc_qcategorydialog.ui \
qt/lc_qimagedialog.ui \
qt/lc_qupdatedialog.ui \
qt/lc_qfinddialog.ui \
qt/lc_qmodellistdialog.ui \
qt/lc_renderdialog.ui \
qt/lc_setsdatabasedialog.ui \
common/lc_partpalettedialog.ui
OTHER_FILES +=
RESOURCES += leocad.qrc
common/texfont.h \
common/project.h \
common/pieceinf.h \
common/piece.h \
common/object.h \
common/minifig.h \
common/light.h \
common/lc_application.h \
common/lc_array.h \
common/lc_category.h \
common/lc_collapsiblewidget.h \
common/lc_colors.h \
common/lc_commands.h \
common/lc_context.h \
common/lc_edgecolordialog.h \
common/lc_file.h \
common/lc_findreplacewidget.h \
common/lc_glextensions.h \
common/lc_global.h \
common/lc_http.h \
common/lc_instructions.h \
common/lc_instructionsdialog.h \
common/lc_library.h \
common/lc_lxf.h \
common/lc_mainwindow.h \
common/lc_math.h \
common/lc_mesh.h \
common/lc_meshloader.h \
common/lc_minifigdialog.h \
common/lc_model.h \
common/lc_pagesetupdialog.h \
common/lc_previewwidget.h \
common/lc_profile.h \
common/lc_scene.h \
common/lc_shortcuts.h \
common/lc_stringcache.h \
common/lc_synth.h \
common/lc_texture.h \
common/lc_view.h \
common/lc_viewsphere.h \
common/lc_viewwidget.h \
common/lc_zipfile.h \
common/lc_partselectionwidget.h \
common/lc_timelinewidget.h \
common/image.h \
common/group.h \
common/camera.h \
qt/lc_qarraydialog.h \
qt/lc_qgroupdialog.h \
qt/lc_qaboutdialog.h \
qt/lc_qeditgroupsdialog.h \
qt/lc_qselectdialog.h \
qt/lc_qpropertiesdialog.h \
qt/lc_qhtmldialog.h \
qt/lc_qpreferencesdialog.h \
qt/lc_qcategorydialog.h \
qt/lc_qimagedialog.h \
qt/lc_qupdatedialog.h \
qt/lc_qutils.h \
qt/lc_qpropertiestree.h \
qt/lc_qcolorpicker.h \
qt/lc_qcolorlist.h \
qt/lc_qmodellistdialog.h \
qt/lc_renderdialog.h \
qt/lc_setsdatabasedialog.h \
common/lc_partpalettedialog.h
FORMS += \
qt/lc_qarraydialog.ui \
qt/lc_qgroupdialog.ui \
qt/lc_qaboutdialog.ui \
qt/lc_qeditgroupsdialog.ui \
qt/lc_qselectdialog.ui \
qt/lc_qpropertiesdialog.ui \
qt/lc_qhtmldialog.ui \
qt/lc_qpreferencesdialog.ui \
qt/lc_qcategorydialog.ui \
qt/lc_qimagedialog.ui \
qt/lc_qupdatedialog.ui \
qt/lc_qmodellistdialog.ui \
qt/lc_renderdialog.ui \
qt/lc_setsdatabasedialog.ui \
common/lc_minifigdialog.ui \
common/lc_pagesetupdialog.ui \
common/lc_partpalettedialog.ui
OTHER_FILES +=
RESOURCES += leocad.qrc resources/stylesheet/stylesheet.qrc
!win32 {
TRANSLATIONS = resources/leocad_pt.ts resources/leocad_fr.ts resources/leocad_de.ts resources/leocad_uk.ts resources/leocad_cs.ts resources/leocad_es.ts
TRANSLATIONS = resources/leocad_pt.ts resources/leocad_fr.ts resources/leocad_de.ts resources/leocad_uk.ts resources/leocad_cs.ts resources/leocad_es.ts
}

View file

@ -30,6 +30,8 @@
<file>resources/action_next.png</file>
<file>resources/action_paint.png</file>
<file>resources/action_pan.png</file>
<file>resources/action_preview_locked.png</file>
<file>resources/action_preview_unlocked.png</file>
<file>resources/action_previous.png</file>
<file>resources/action_roll.png</file>
<file>resources/action_rotate.png</file>
@ -61,6 +63,11 @@
<file>resources/edit_copy.png</file>
<file>resources/edit_cut.png</file>
<file>resources/edit_find.png</file>
<file>resources/edit_find_next.png</file>
<file>resources/edit_find_previous.png</file>
<file>resources/edit_find_all.png</file>
<file>resources/edit_replace_next.png</file>
<file>resources/edit_replace_all.png</file>
<file>resources/edit_paste.png</file>
<file>resources/edit_redo.png</file>
<file>resources/edit_snap_angle.png</file>
@ -76,7 +83,7 @@
<file>resources/time_next.png</file>
<file>resources/time_previous.png</file>
<file>resources/time_stop.png</file>
<file>resources/leocad.png</file>
<file alias="resources/leocad.png">tools/icon/64x64/apps/leocad.png</file>
<file>resources/help_homepage.png</file>
<file>resources/view_zoomextents.png</file>
<file>resources/view_split_horizontal.png</file>
@ -94,6 +101,13 @@
<file>resources/parts_cancel.png</file>
<file>resources/archive.png</file>
<file>resources/library.zip</file>
<file>resources/studlogo1.zip</file>
<file>resources/studlogo2.zip</file>
<file>resources/studlogo3.zip</file>
<file>resources/studlogo4.zip</file>
<file>resources/studlogo5.zip</file>
<file>resources/studslegostyle1.zip</file>
<file>resources/studslegostyle2.zip</file>
<file>resources/ldconfig.ldr</file>
<file>resources/minifig.ini</file>
<file>resources/ldraw.xml</file>

View file

@ -63,7 +63,7 @@
<key>CFBundleSignature</key>
<string>LCAD</string>
<key>CFBundleVersion</key>
<string>19.07.1</string>
<string>21.01.0</string>
<key>CFBundleDisplayName</key>
<string>LeoCAD</string>
<key>CFBundleName</key>

View file

@ -2,8 +2,9 @@
#include "lc_qaboutdialog.h"
#include "ui_lc_qaboutdialog.h"
#include "lc_mainwindow.h"
#include "view.h"
#include "lc_view.h"
#include "lc_glextensions.h"
#include "lc_viewwidget.h"
lcQAboutDialog::lcQAboutDialog(QWidget *parent) :
QDialog(parent),
@ -17,25 +18,26 @@ lcQAboutDialog::lcQAboutDialog(QWidget *parent) :
ui->version->setText(tr("LeoCAD Version %1").arg(QString::fromLatin1(LC_VERSION_TEXT)));
#endif
QGLWidget* Widget = (QGLWidget*)gMainWindow->GetActiveView()->mWidget;
QGLFormat Format = Widget->context()->format();
lcViewWidget* Widget = gMainWindow->GetActiveView()->GetWidget();
QSurfaceFormat Format = Widget->context()->format();
int ColorDepth = Format.redBufferSize() + Format.greenBufferSize() + Format.blueBufferSize() + Format.alphaBufferSize();
QString QtVersionFormat = tr("Qt Version %1 (compiled with %2)\n\n");
QString QtVersion = QtVersionFormat.arg(qVersion(), QT_VERSION_STR);
QString VersionFormat = tr("OpenGL Version %1 (GLSL %2)\n%3 - %4\n\n");
QString Version = VersionFormat.arg(QString((const char*)glGetString(GL_VERSION)), QString((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)), QString((const char*)glGetString(GL_RENDERER)), QString((const char*)glGetString(GL_VENDOR)));
QString BuffersFormat = tr("Color Buffer: %1 bits %2 %3\nDepth Buffer: %4 bits\nStencil Buffer: %5 bits\n\n");
QString Buffers = BuffersFormat.arg(QString::number(ColorDepth), Format.rgba() ? "RGBA" : tr("indexed"), Format.doubleBuffer() ? tr("double buffered") : QString(), QString::number(Format.depthBufferSize()), QString::number(Format.stencilBufferSize()));
const QString QtVersionFormat = tr("Qt Version %1 (compiled with %2)\n\n");
const QString QtVersion = QtVersionFormat.arg(qVersion(), QT_VERSION_STR);
const QString VersionFormat = tr("OpenGL Version %1 (GLSL %2)\n%3 - %4\n\n");
const QString Version = VersionFormat.arg(QString((const char*)glGetString(GL_VERSION)), QString((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)), QString((const char*)glGetString(GL_RENDERER)), QString((const char*)glGetString(GL_VENDOR)));
const QString BuffersFormat = tr("Color Buffer: %1 bits\nDepth Buffer: %2 bits\nStencil Buffer: %3 bits\n\n");
const QString Buffers = BuffersFormat.arg(QString::number(ColorDepth), QString::number(Format.depthBufferSize()), QString::number(Format.stencilBufferSize()));
QString ExtensionsFormat = tr("GL_ARB_vertex_buffer_object extension: %1\nGL_ARB_framebuffer_object extension: %2\nGL_EXT_framebuffer_object extension: %3\nGL_EXT_blend_func_separate: %4\nGL_EXT_texture_filter_anisotropic extension: %5\n");
QString VertexBufferObject = gSupportsVertexBufferObject ? tr("Supported") : tr("Not supported");
QString FramebufferObjectARB = gSupportsFramebufferObjectARB ? tr("Supported") : tr("Not supported");
QString FramebufferObjectEXT = gSupportsFramebufferObjectEXT ? tr("Supported") : tr("Not supported");
QString BlendFuncSeparateEXT = gSupportsBlendFuncSeparate ? tr("Supported") : tr("Not supported");
QString Anisotropic = gSupportsAnisotropic ? tr("Supported (max %1)").arg(gMaxAnisotropy) : tr("Not supported");
QString Extensions = ExtensionsFormat.arg(VertexBufferObject, FramebufferObjectARB, FramebufferObjectEXT, BlendFuncSeparateEXT, Anisotropic);
const QString ExtensionsFormat = tr("Buffers: %1\nShaders: %2\nFramebuffers: %3\nBlendFuncSeparate: %4\nAnisotropic: %5\n");
const QString VertexBuffers = gSupportsVertexBufferObject ? tr("Supported") : tr("Not supported");
const QString Shaders = gSupportsShaderObjects ? tr("Supported") : tr("Not supported");
const QString Framebuffers = gSupportsFramebufferObject ? tr("Supported") : tr("Not supported");
const QString BlendFuncSeparate = gSupportsBlendFuncSeparate ? tr("Supported") : tr("Not supported");
const QString Anisotropic = gSupportsAnisotropic ? tr("Supported (max %1)").arg(gMaxAnisotropy) : tr("Not supported");
const QString Extensions = ExtensionsFormat.arg(VertexBuffers, Shaders, Framebuffers, BlendFuncSeparate, Anisotropic);
ui->info->setText(QtVersion + Version + Buffers + Extensions);
}

View file

@ -1,54 +1,204 @@
#include <QtGui>
#include "lc_global.h"
#include "lc_qcolorlist.h"
#include "lc_application.h"
#include "lc_library.h"
#include "lc_colors.h"
lcQColorList::lcQColorList(QWidget *parent)
: QWidget(parent)
void lcDrawNoColorRect(QPainter& Painter, const QRect& Rect)
{
mCellRects = new QRect[gNumUserColors];
mCellColors = new int[gNumUserColors];
mNumCells = 0;
Painter.setBrush(Qt::black);
Painter.drawRect(Rect);
mCurCell = 0;
const int SquareSize = 3;
int Column = 0;
for (;;)
{
int x = Rect.left() + 1 + Column * SquareSize;
if (x >= Rect.right())
break;
int Row = Column & 1;
for (;;)
{
int y = Rect.top() + 1 + Row * SquareSize;
if (y >= Rect.bottom())
break;
QRect GridRect(x, y, SquareSize, SquareSize);
if (GridRect.right() > Rect.right())
GridRect.setRight(Rect.right());
if (GridRect.bottom() > Rect.bottom())
GridRect.setBottom(Rect.bottom());
Painter.fillRect(GridRect, Qt::white);
Row += 2;
}
Column++;
}
}
lcQColorList::lcQColorList(QWidget* Parent, bool AllowNoColor)
: QWidget(Parent), mAllowNoColor(AllowNoColor)
{
setFocusPolicy(Qt::StrongFocus);
UpdateCells();
connect(lcGetPiecesLibrary(), &lcPiecesLibrary::ColorsLoaded, this, &lcQColorList::ColorsLoaded);
}
void lcQColorList::UpdateCells()
{
mCells.clear();
mGroups.clear();
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
{
lcColorGroup* Group = &gColorGroups[GroupIdx];
lcColorListGroup ListGroup;
for (int ColorIndex : Group->Colors)
{
mCells.emplace_back(lcColorListCell{ QRect(), ColorIndex });
ListGroup.Name = Group->Name;
ListGroup.Cells.emplace_back(mCells.size());
}
mGroups.emplace_back(std::move(ListGroup));
}
if (mAllowNoColor)
{
mCells.emplace_back(lcColorListCell{ QRect(), lcGetColorIndex(LC_COLOR_NOCOLOR) });
mGroups[LC_COLORGROUP_SPECIAL].Cells.emplace_back(mCells.size());
}
mColumns = 14;
mRows = 0;
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
{
lcColorGroup* Group = &gColorGroups[GroupIdx];
for (int Color: Group->Colors)
mCellColors[mNumCells++] = Color;
mRows += ((int)Group->Colors.size() + mColumns - 1) / mColumns;
}
mWidth = 0;
mHeight = 0;
for (const lcColorListGroup& Group : mGroups)
mRows += ((int)Group.Cells.size() + mColumns - 1) / mColumns;
QFontMetrics Metrics(font());
int TextHeight = 0;
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
for (lcColorListGroup& Group : mGroups)
{
lcColorGroup* Group = &gColorGroups[GroupIdx];
Group.Rect = Metrics.boundingRect(rect(), Qt::TextSingleLine | Qt::AlignCenter, Group.Name);
mGroupRects[GroupIdx] = Metrics.boundingRect(rect(), Qt::TextSingleLine | Qt::AlignCenter, Group->Name);
TextHeight += mGroupRects[GroupIdx].height();
TextHeight += Group.Rect.height();
}
mPreferredHeight = TextHeight + 10 * mRows;
setFocusPolicy(Qt::StrongFocus);
setMinimumHeight(TextHeight + 5 * mRows);
}
lcQColorList::~lcQColorList()
void lcQColorList::UpdateRects()
{
delete[] mCellRects;
delete[] mCellColors;
QFontMetrics Metrics(font());
int TextHeight = 0;
for (lcColorListGroup& Group : mGroups)
{
Group.Rect = Metrics.boundingRect(rect(), Qt::TextSingleLine | Qt::AlignCenter, Group.Name);
TextHeight += Group.Rect.height();
}
mPreferredHeight = TextHeight + 10 * mRows;
float CellWidth = (float)(width() + 1) / (float)mColumns;
float CellHeight = (float)(height() - TextHeight) / (float)mRows;
while (CellWidth / CellHeight > 1.5f)
{
mColumns++;
mRows = 0;
for (const lcColorListGroup& Group : mGroups)
mRows += ((int)Group.Cells.size() + mColumns - 1) / mColumns;
CellWidth = (float)(width() + 1) / (float)mColumns;
CellHeight = (float)(height() - TextHeight) / (float)mRows;
if (mRows <= LC_NUM_COLORGROUPS)
break;
}
while (CellHeight / CellWidth > 1.5f)
{
mColumns--;
mRows = 0;
for (const lcColorListGroup& Group : mGroups)
mRows += ((int)Group.Cells.size() + mColumns - 1) / mColumns;
CellWidth = (float)(width() + 1) / (float)mColumns;
CellHeight = (float)(height() - TextHeight) / (float)mRows;
if (mColumns <= 5)
break;
}
int CurCell = 0;
float GroupY = 0.0f;
int TotalRows = 1;
for (lcColorListGroup& Group : mGroups)
{
int CurColumn = 0;
int NumRows = 0;
Group.Rect = QRect(0, (int)GroupY, width(), Group.Rect.height());
GroupY += Group.Rect.height();
for (size_t ColorIdx = 0; ColorIdx < Group.Cells.size(); ColorIdx++)
{
const int Left = CellWidth * CurColumn - 1;
const int Right = (CurColumn + 1) * CellWidth - 1;
const int Top = GroupY + CellHeight * NumRows;
const int Bottom = (TotalRows != mRows) ? GroupY + CellHeight * (NumRows + 1) : height() - 1;
mCells[CurCell].Rect = QRect(Left, Top, Right - Left, Bottom - Top);
CurColumn++;
if (CurColumn == mColumns)
{
CurColumn = 0;
NumRows++;
TotalRows++;
}
CurCell++;
}
if (CurColumn != 0)
{
NumRows++;
TotalRows++;
}
GroupY += NumRows * CellHeight;
}
}
void lcQColorList::ColorsLoaded()
{
UpdateCells();
UpdateRects();
setCurrentColor(lcGetColorIndex(mColorCode));
update();
}
QSize lcQColorList::sizeHint() const
@ -56,15 +206,15 @@ QSize lcQColorList::sizeHint() const
return QSize(200, mPreferredHeight);
}
void lcQColorList::setCurrentColor(int colorIndex)
void lcQColorList::setCurrentColor(int ColorIndex)
{
for (int CellIdx = 0; CellIdx < mNumCells; CellIdx++)
for (size_t CellIndex = 0; CellIndex < mCells.size(); CellIndex++)
{
if (mCellColors[CellIdx] != colorIndex)
continue;
SelectCell(CellIdx);
break;
if (mCells[CellIndex].ColorIndex == ColorIndex)
{
SelectCell(CellIndex);
break;
}
}
}
@ -74,19 +224,22 @@ bool lcQColorList::event(QEvent *event)
{
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
for (int CellIdx = 0; CellIdx < mNumCells; CellIdx++)
for (size_t CellIndex = 0; CellIndex < mCells.size(); CellIndex++)
{
if (!mCellRects[CellIdx].contains(helpEvent->pos()))
if (!mCells[CellIndex].Rect.contains(helpEvent->pos()))
continue;
lcColor* color = &gColorList[mCellColors[CellIdx]];
lcColor* color = &gColorList[mCells[CellIndex].ColorIndex];
QColor rgb(color->Value[0] * 255, color->Value[1] * 255, color->Value[2] * 255);
QImage image(16, 16, QImage::Format_RGB888);
image.fill(rgb);
QPainter painter(&image);
painter.setPen(Qt::darkGray);
painter.drawRect(0, 0, image.width() - 1, image.height() - 1);
if (color->Code != LC_COLOR_NOCOLOR)
painter.drawRect(0, 0, image.width() - 1, image.height() - 1);
else
lcDrawNoColorRect(painter, QRect(0, 0, image.width() - 1, image.height() - 1));
painter.end();
QByteArray ba;
@ -95,9 +248,18 @@ bool lcQColorList::event(QEvent *event)
image.save(&buffer, "PNG");
buffer.close();
int colorIndex = mCellColors[CellIdx];
const char* format = "<table><tr><td style=\"vertical-align:middle\"><img src=\"data:image/png;base64,%1\"/></td><td>%2 (%3)</td></tr></table>";
QString text = QString(format).arg(QString(buffer.data().toBase64()), gColorList[colorIndex].Name, QString::number(gColorList[colorIndex].Code));
int colorIndex = mCells[CellIndex].ColorIndex;
QString text;
if (color->Code != LC_COLOR_NOCOLOR)
{
const char* format = "<table><tr><td style=\"vertical-align:middle\"><img src=\"data:image/png;base64,%1\"/></td><td>%2 (%3)</td></tr></table>";
text = QString(format).arg(QString(buffer.data().toBase64()), gColorList[colorIndex].Name, QString::number(gColorList[colorIndex].Code));
}
else
{
const char* format = "<table><tr><td style=\"vertical-align:middle\"><img src=\"data:image/png;base64,%1\"/></td><td>%2</td></tr></table>";
text = QString(format).arg(QString(buffer.data().toBase64()), gColorList[colorIndex].Name);
}
QToolTip::showText(helpEvent->globalPos(), text);
return true;
@ -132,13 +294,13 @@ bool lcQColorList::event(QEvent *event)
void lcQColorList::mousePressEvent(QMouseEvent* MouseEvent)
{
for (int CellIdx = 0; CellIdx < mNumCells; CellIdx++)
for (size_t CellIndex = 0; CellIndex < mCells.size(); CellIndex++)
{
if (!mCellRects[CellIdx].contains(MouseEvent->pos()))
if (!mCells[CellIndex].Rect.contains(MouseEvent->pos()))
continue;
SelectCell(CellIdx);
emit colorSelected(mCellColors[CellIdx]);
SelectCell(CellIndex);
emit colorSelected(mCells[CellIndex].ColorIndex);
break;
}
@ -155,7 +317,7 @@ void lcQColorList::mouseMoveEvent(QMouseEvent* MouseEvent)
return;
QMimeData* MimeData = new QMimeData;
MimeData->setData("application/vnd.leocad-color", QString::number(mCellColors[mCurCell]).toLatin1());
MimeData->setData("application/vnd.leocad-color", QString::number(mCells[mCurrentCell].ColorIndex).toLatin1());
QDrag* Drag = new QDrag(this);
Drag->setMimeData(MimeData);
@ -165,232 +327,142 @@ void lcQColorList::mouseMoveEvent(QMouseEvent* MouseEvent)
void lcQColorList::keyPressEvent(QKeyEvent *event)
{
int NewCell = mCurCell;
size_t NewCell = mCurrentCell;
if (event->key() == Qt::Key_Left)
{
if (mCurCell > 0)
NewCell = mCurCell - 1;
if (mCurrentCell > 0)
NewCell = mCurrentCell - 1;
}
else if (event->key() == Qt::Key_Right)
{
if (mCurCell < mNumCells - 1)
NewCell = mCurCell + 1;
if (mCurrentCell < mCells.size() - 1)
NewCell = mCurrentCell + 1;
}
else if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down)
{
if (mCurCell < 0 || mCurCell >= mNumCells)
mCurCell = 0;
if (mCurrentCell >= mCells.size())
mCurrentCell = 0;
int CurGroup = 0;
int NumCells = 0;
size_t CurGroup = 0;
size_t NumCells = 0;
for (CurGroup = 0; CurGroup < LC_NUM_COLORGROUPS; CurGroup++)
for (CurGroup = 0; CurGroup < mGroups.size(); CurGroup++)
{
int NumColors = (int)gColorGroups[CurGroup].Colors.size();
int NumColors = (int)mGroups[CurGroup].Cells.size();
if (mCurCell < NumCells + NumColors)
if (mCurrentCell < NumCells + NumColors)
break;
NumCells += NumColors;
}
int Row = (mCurCell - NumCells) / mColumns;
int Column = (mCurCell - NumCells) % mColumns;
size_t Row = (mCurrentCell - NumCells) / mColumns;
size_t Column = (mCurrentCell - NumCells) % mColumns;
if (event->key() == Qt::Key_Up)
{
if (Row > 0)
NewCell = mCurCell - mColumns;
NewCell = mCurrentCell - mColumns;
else if (CurGroup > 0)
{
size_t NumColors = gColorGroups[CurGroup - 1].Colors.size();
int NumColumns = NumColors % mColumns;
size_t NumColors = mGroups[CurGroup - 1].Cells.size();
size_t NumColumns = NumColors % mColumns;
if (NumColumns <= Column + 1)
NewCell = mCurCell - NumColumns - mColumns;
if (NumColumns < Column + 1)
NewCell = mCurrentCell - NumColumns - mColumns;
else
NewCell = mCurCell - NumColumns;
NewCell = mCurrentCell - NumColumns;
}
}
else if (event->key() == Qt::Key_Down)
{
int NumColors = (int)gColorGroups[CurGroup].Colors.size();
int NumColors = (int)mGroups[CurGroup].Cells.size();
if (mCurCell + mColumns < NumCells + NumColors)
NewCell = mCurCell + mColumns;
if (mCurrentCell + mColumns < NumCells + NumColors)
NewCell = mCurrentCell + mColumns;
else
{
int NumColumns = NumColors % mColumns;
size_t NumColumns = NumColors % mColumns;
if (NumColumns > Column)
{
if (mCurCell + NumColumns < mNumCells)
NewCell = mCurCell + NumColumns;
if (mCurrentCell + NumColumns < mCells.size())
NewCell = mCurrentCell + NumColumns;
}
else
NewCell = mCurCell + mColumns + NumColumns;
NewCell = mCurrentCell + mColumns + NumColumns;
}
}
}
else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
{
emit colorSelected(mCellColors[mCurCell]);
emit colorSelected(mCells[mCurrentCell].ColorIndex);
}
if (NewCell != mCurCell)
if (NewCell != mCurrentCell)
SelectCell(NewCell);
else
QWidget::keyPressEvent(event);
}
void lcQColorList::resizeEvent(QResizeEvent *event)
void lcQColorList::resizeEvent(QResizeEvent* Event)
{
if (mWidth == width() && mHeight == height())
return;
QFontMetrics Metrics(font());
int TextHeight = 0;
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
{
lcColorGroup* Group = &gColorGroups[GroupIdx];
mGroupRects[GroupIdx] = Metrics.boundingRect(rect(), Qt::TextSingleLine | Qt::AlignCenter, Group->Name);
TextHeight += mGroupRects[GroupIdx].height();
}
mPreferredHeight = TextHeight + 10 * mRows;
float CellWidth = (float)(width() + 1) / (float)mColumns;
float CellHeight = (float)(height() - TextHeight) / (float)mRows;
while (CellWidth / CellHeight > 1.5f)
{
mColumns++;
mRows = 0;
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
{
lcColorGroup* Group = &gColorGroups[GroupIdx];
mRows += ((int)Group->Colors.size() + mColumns - 1) / mColumns;
}
CellWidth = (float)(width() + 1) / (float)mColumns;
CellHeight = (float)(height() - TextHeight) / (float)mRows;
if (mRows <= LC_NUM_COLORGROUPS)
break;
}
while (CellHeight / CellWidth > 1.5f)
{
mColumns--;
mRows = 0;
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
{
lcColorGroup* Group = &gColorGroups[GroupIdx];
mRows += ((int)Group->Colors.size() + mColumns - 1) / mColumns;
}
CellWidth = (float)(width() + 1) / (float)mColumns;
CellHeight = (float)(height() - TextHeight) / (float)mRows;
if (mColumns <= 5)
break;
}
int CurCell = 0;
float GroupY = 0.0f;
int TotalRows = 1;
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
{
lcColorGroup* Group = &gColorGroups[GroupIdx];
int CurColumn = 0;
int NumRows = 0;
mGroupRects[GroupIdx] = QRect(0, (int)GroupY, width(), mGroupRects[GroupIdx].height());
GroupY += mGroupRects[GroupIdx].height();
for (size_t ColorIdx = 0; ColorIdx < Group->Colors.size(); ColorIdx++)
{
const int Left = CellWidth * CurColumn - 1;
const int Right = (CurColumn + 1) * CellWidth - 1;
const int Top = GroupY + CellHeight * NumRows;
const int Bottom = (TotalRows != mRows) ? GroupY + CellHeight * (NumRows + 1) : height();
mCellRects[CurCell] = QRect(Left, Top, Right - Left, Bottom - Top);
CurColumn++;
if (CurColumn == mColumns)
{
CurColumn = 0;
NumRows++;
TotalRows++;
}
CurCell++;
}
if (CurColumn != 0)
{
NumRows++;
TotalRows++;
}
GroupY += NumRows * CellHeight;
}
UpdateRects();
mWidth = width();
mHeight = height();
QWidget::resizeEvent(event);
QWidget::resizeEvent(Event);
}
void lcQColorList::paintEvent(QPaintEvent *event)
void lcQColorList::paintEvent(QPaintEvent* Event)
{
Q_UNUSED(event);
Q_UNUSED(Event);
QPainter painter(this);
QPainter Painter(this);
painter.fillRect(rect(), palette().brush(QPalette::Base));
Painter.fillRect(rect(), palette().brush(QPalette::Window));
painter.setFont(font());
painter.setPen(palette().color(QPalette::Text));
Painter.setFont(font());
Painter.setPen(palette().color(QPalette::Text));
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
for (const lcColorListGroup& Group : mGroups)
Painter.drawText(Group.Rect, Qt::TextSingleLine | Qt::AlignLeft, Group.Name);
Painter.setPen(palette().color(QPalette::Shadow));
for (size_t CellIndex = 0; CellIndex < mCells.size(); CellIndex++)
{
lcColorGroup* Group = &gColorGroups[GroupIdx];
const lcColor* Color = &gColorList[mCells[CellIndex].ColorIndex];
painter.drawText(mGroupRects[GroupIdx], Qt::TextSingleLine | Qt::AlignCenter, Group->Name);
const QRect& Rect = mCells[CellIndex].Rect;
if (Color->Code != LC_COLOR_NOCOLOR)
{
QColor CellColor(Color->Value[0] * 255, Color->Value[1] * 255, Color->Value[2] * 255);
Painter.setBrush(CellColor);
Painter.drawRect(Rect);
}
else
lcDrawNoColorRect(Painter, Rect);
}
painter.setPen(palette().color(QPalette::Shadow));
for (int CellIdx = 0; CellIdx < mNumCells; CellIdx++)
if (mCurrentCell < mCells.size())
{
lcColor* Color = &gColorList[mCellColors[CellIdx]];
QColor CellColor(Color->Value[0] * 255, Color->Value[1] * 255, Color->Value[2] * 255);
painter.setBrush(CellColor);
painter.drawRect(mCellRects[CellIdx]);
}
if (mCurCell < mNumCells)
{
lcColor* Color = &gColorList[mCellColors[mCurCell]];
const lcColor* Color = &gColorList[mCells[mCurrentCell].ColorIndex];
QColor EdgeColor(255 - Color->Value[0] * 255, 255 - Color->Value[1] * 255, 255 - Color->Value[2] * 255);
QColor CellColor(Color->Value[0] * 255, Color->Value[1] * 255, Color->Value[2] * 255);
painter.setPen(EdgeColor);
painter.setBrush(CellColor);
Painter.setPen(EdgeColor);
Painter.setBrush(Qt::NoBrush);
QRect CellRect = mCellRects[mCurCell];
QRect CellRect = mCells[mCurrentCell].Rect;
CellRect.adjust(1, 1, -1, -1);
painter.drawRect(CellRect);
Painter.drawRect(CellRect);
/*
if (GetFocus() == this)
@ -402,36 +474,17 @@ void lcQColorList::paintEvent(QPaintEvent *event)
}
}
void lcQColorList::SelectCell(int CellIdx)
void lcQColorList::SelectCell(size_t CellIndex)
{
if (CellIdx < 0 || CellIdx >= mNumCells)
if (CellIndex >= mCells.size())
return;
if (CellIdx == mCurCell)
if (CellIndex == mCurrentCell)
return;
update(mCellRects[mCurCell]);
update(mCellRects[CellIdx]);
mCurCell = CellIdx;
mCurrentCell = CellIndex;
mColorCode = lcGetColorCode(mCells[CellIndex].ColorIndex);
emit colorChanged(mCellColors[mCurCell]);
emit colorChanged(mCells[mCurrentCell].ColorIndex);
update();
}
#if 0
*/
void ColorPickerButton::focusInEvent(QFocusEvent *e)
{
setFrameShadow(Raised);
update();
QFrame::focusOutEvent(e);
}
void ColorPickerButton::focusOutEvent(QFocusEvent *e)
{
setFrameShadow(Raised);
update();
QFrame::focusOutEvent(e);
}
#endif

View file

@ -1,15 +1,27 @@
#pragma once
#include <QWidget>
#include "lc_colors.h"
struct lcColorListCell
{
QRect Rect;
int ColorIndex;
};
struct lcColorListGroup
{
QRect Rect;
QString Name;
std::vector<size_t> Cells;
};
void lcDrawNoColorRect(QPainter& Painter, const QRect& Rect);
class lcQColorList : public QWidget
{
Q_OBJECT
public:
lcQColorList(QWidget *parent = 0);
~lcQColorList();
lcQColorList(QWidget* Parent = nullptr, bool AllowNoColor = false);
~lcQColorList() = default;
QSize sizeHint() const override;
@ -19,7 +31,14 @@ signals:
void colorChanged(int colorIndex);
void colorSelected(int colorIndex);
protected slots:
void ColorsLoaded();
protected:
void UpdateCells();
void UpdateRects();
void SelectCell(size_t CellIndex);
bool event(QEvent* Event) override;
void paintEvent(QPaintEvent* PaintEvent) override;
void resizeEvent(QResizeEvent* ResizeEvent) override;
@ -27,20 +46,19 @@ protected:
void mouseMoveEvent(QMouseEvent* MouseEvent) override;
void keyPressEvent(QKeyEvent* KeyEvent) override;
void SelectCell(int CellIdx);
std::vector<lcColorListCell> mCells;
std::vector<lcColorListGroup> mGroups;
QRect mGroupRects[LC_NUM_COLORGROUPS];
QRect* mCellRects;
int* mCellColors;
int mNumCells;
size_t mCurrentCell = 0;
quint32 mColorCode = 0;
int mColumns;
int mRows;
int mWidth;
int mHeight;
int mPreferredHeight;
int mColumns = 0;
int mRows = 0;
int mWidth = 0;
int mHeight = 0;
int mPreferredHeight = 0;
bool mAllowNoColor;
int mCurCell;
QPoint mDragStartPosition;
};

View file

@ -3,8 +3,8 @@
#include "lc_qcolorlist.h"
#include "lc_colors.h"
lcQColorPickerPopup::lcQColorPickerPopup(QWidget *parent, int colorIndex)
: QFrame(parent, Qt::Popup)
lcQColorPickerPopup::lcQColorPickerPopup(QWidget* Parent, int ColorIndex, bool AllowNoColor)
: QFrame(Parent, Qt::Popup)
{
setFrameStyle(QFrame::StyledPanel);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
@ -16,13 +16,13 @@ lcQColorPickerPopup::lcQColorPickerPopup(QWidget *parent, int colorIndex)
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
colorList = new lcQColorList(this);
colorList = new lcQColorList(this, AllowNoColor);
connect(colorList, SIGNAL(colorChanged(int)), this, SLOT(colorChanged(int)));
connect(colorList, SIGNAL(colorSelected(int)), this, SLOT(colorSelected(int)));
layout->addWidget(colorList);
colorList->blockSignals(true);
colorList->setCurrentColor(colorIndex);
colorList->setCurrentColor(ColorIndex);
colorList->blockSignals(false);
eventLoop = nullptr;
@ -75,17 +75,15 @@ void lcQColorPickerPopup::showEvent(QShowEvent *)
colorList->setFocus();
}
lcQColorPicker::lcQColorPicker(QWidget *parent)
: QPushButton(parent)
lcQColorPicker::lcQColorPicker(QWidget* Parent, bool AllowNoColor)
: QPushButton(Parent), mAllowNoColor(AllowNoColor)
{
setFocusPolicy(Qt::StrongFocus);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
setAutoDefault(false);
setCheckable(true);
initialColorIndex = 0;
currentColorIndex = 0;
updateIcon();
UpdateIcon();
connect(this, SIGNAL(toggled(bool)), SLOT(buttonPressed(bool)));
}
@ -106,12 +104,12 @@ void lcQColorPicker::setCurrentColorCode(int colorCode)
int lcQColorPicker::currentColor() const
{
return currentColorIndex;
return mCurrentColorIndex;
}
int lcQColorPicker::currentColorCode() const
{
return gColorList[currentColorIndex].Code;
return gColorList[mCurrentColorIndex].Code;
}
void lcQColorPicker::buttonPressed(bool toggled)
@ -119,7 +117,7 @@ void lcQColorPicker::buttonPressed(bool toggled)
if (!toggled)
return;
lcQColorPickerPopup *popup = new lcQColorPickerPopup(this, currentColorIndex);
lcQColorPickerPopup *popup = new lcQColorPickerPopup(this, mCurrentColorIndex, mAllowNoColor);
connect(popup, SIGNAL(changed(int)), SLOT(changed(int)));
connect(popup, SIGNAL(selected(int)), SLOT(selected(int)));
connect(popup, SIGNAL(hid()), SLOT(popupClosed()));
@ -146,26 +144,34 @@ void lcQColorPicker::buttonPressed(bool toggled)
popup->show();
}
void lcQColorPicker::updateIcon()
void lcQColorPicker::UpdateIcon()
{
int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize);
QPixmap pix(iconSize, iconSize);
const int IconSize = 14;//style()->pixelMetric(QStyle::PM_SmallIconSize);
QPixmap Pixmap(IconSize, IconSize);
QPainter p(&pix);
QPainter Painter(&Pixmap);
lcColor* color = &gColorList[currentColorIndex];
p.setPen(Qt::darkGray);
p.setBrush(QColor::fromRgbF(color->Value[0], color->Value[1], color->Value[2]));
p.drawRect(0, 0, pix.width() - 1, pix.height() - 1);
p.end();
Painter.setPen(Qt::darkGray);
setIcon(QIcon(pix));
const lcColor* Color = &gColorList[mCurrentColorIndex];
if (Color->Code != LC_COLOR_NOCOLOR)
{
Painter.setBrush(QColor::fromRgbF(Color->Value[0], Color->Value[1], Color->Value[2]));
Painter.drawRect(0, 0, Pixmap.width() - 1, Pixmap.height() - 1);
}
else
lcDrawNoColorRect(Painter, QRect(0, 0, Pixmap.width() - 1, Pixmap.height() - 1));
Painter.end();
setIcon(QIcon(Pixmap));
}
void lcQColorPicker::popupClosed()
{
if (initialColorIndex != currentColorIndex)
changed(initialColorIndex);
if (mInitialColorIndex != mCurrentColorIndex)
changed(mInitialColorIndex);
setChecked(false);
setFocus();
@ -173,19 +179,19 @@ void lcQColorPicker::popupClosed()
void lcQColorPicker::changed(int colorIndex)
{
if (colorIndex == currentColorIndex)
if (colorIndex == mCurrentColorIndex)
return;
currentColorIndex = colorIndex;
updateIcon();
mCurrentColorIndex = colorIndex;
UpdateIcon();
repaint();
emit colorChanged(currentColorIndex);
emit colorChanged(mCurrentColorIndex);
}
void lcQColorPicker::selected(int colorIndex)
{
initialColorIndex = colorIndex;
mInitialColorIndex = colorIndex;
changed(colorIndex);
}

Some files were not shown because too many files have changed in this diff Show more