commit
cfd630f4ac
49
.travis.yml
49
.travis.yml
|
@ -1,24 +1,27 @@
|
||||||
language: c
|
language: c
|
||||||
os:
|
git:
|
||||||
- linux
|
submodules: false
|
||||||
- osx
|
jobs:
|
||||||
sudo: required
|
include:
|
||||||
dist: trusty
|
- stage: test
|
||||||
osx_image: xcode8.2
|
name: "Debian"
|
||||||
install:
|
os: linux
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./.travis/install-debian.sh; fi
|
dist: bionic
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./.travis/install-macos.sh; fi
|
install: ./.travis/install-debian.sh
|
||||||
script:
|
script: ./.travis/build-debian.sh
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./.travis/build-debian.sh; fi
|
- stage: deploy
|
||||||
# the awk command is a workaround for https://github.com/travis-ci/travis-ci/issues/4704.
|
name: "OSX"
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./.travis/build-macos.sh | awk '/.{0,32}/ {print $0}'; fi
|
os: osx
|
||||||
deploy:
|
osx_image: xcode8.3
|
||||||
- provider: releases
|
install: ./.travis/install-macos.sh
|
||||||
api_key:
|
# the awk command is a workaround for https://github.com/travis-ci/travis-ci/issues/4704.
|
||||||
secure: dDlkIawHcODlW9B/20/cQCtzeoocvs0hKuNngRKXKqzXLWTRq33oq/B7+39tAixWbmv6exTpijiKrRNFiSCW5Z4iwHLwaRD4XJznxw63e/Hus/dxg2Tvqx7XFpkCz8mT1Z+gZQE5YxAngeZPpI/sZbZtF1UO3yH5eLeeokZ15p26ZskQUPoYuzrTgTzYL3XfpG3F+20rNBawH1ycsCTVD/08/n31d2m3CrKAsbW7er92ek6w4fzKr7NW8WeXjrPJETVpw5fQg1Od3pRGW8dPQaJcvKQEogMp8Mm0ETYd0qigg89/giBz7QwOgmAWQ4dH+DfZH4Ojl//127QztBolMvyDMQBykWrtJoGcij05sT6K2IJr2FHeUBO12MAEdjiVvhQj3DtTzjPiZAHHDBSLWxLKWWhlhHE4pq7g1MQhqXkaAHI2BLNzwLmaowbMT0bECf9yfz6xx18h6XPQFX44oOktraobVALFlyHqeKa8zdcUt22LF6uAL1m5dxL0tny3eXCIPE4UH/RZgua/cHV9G3cUvKQa/QnFSLRhvWVSbGB+7YsHouBJcsUOOW1gmd5442XuC7mpppccRldh+GSxUk6TBJRAx7TeQ0ybDUaoco9MUqp2twv3KreR2+8Q12PDaAhfQVNEGdF3wTm1sShImjCN4VN3eSLlBEbve1QRQXM=
|
script: ./.travis/build-macos.sh | awk '/.{0,32}/ {print $0}'
|
||||||
skip_cleanup: true
|
deploy:
|
||||||
file: build/SolveSpace.dmg
|
provider: releases
|
||||||
on:
|
api_key:
|
||||||
repo: solvespace/solvespace
|
secure: dDlkIawHcODlW9B/20/cQCtzeoocvs0hKuNngRKXKqzXLWTRq33oq/B7+39tAixWbmv6exTpijiKrRNFiSCW5Z4iwHLwaRD4XJznxw63e/Hus/dxg2Tvqx7XFpkCz8mT1Z+gZQE5YxAngeZPpI/sZbZtF1UO3yH5eLeeokZ15p26ZskQUPoYuzrTgTzYL3XfpG3F+20rNBawH1ycsCTVD/08/n31d2m3CrKAsbW7er92ek6w4fzKr7NW8WeXjrPJETVpw5fQg1Od3pRGW8dPQaJcvKQEogMp8Mm0ETYd0qigg89/giBz7QwOgmAWQ4dH+DfZH4Ojl//127QztBolMvyDMQBykWrtJoGcij05sT6K2IJr2FHeUBO12MAEdjiVvhQj3DtTzjPiZAHHDBSLWxLKWWhlhHE4pq7g1MQhqXkaAHI2BLNzwLmaowbMT0bECf9yfz6xx18h6XPQFX44oOktraobVALFlyHqeKa8zdcUt22LF6uAL1m5dxL0tny3eXCIPE4UH/RZgua/cHV9G3cUvKQa/QnFSLRhvWVSbGB+7YsHouBJcsUOOW1gmd5442XuC7mpppccRldh+GSxUk6TBJRAx7TeQ0ybDUaoco9MUqp2twv3KreR2+8Q12PDaAhfQVNEGdF3wTm1sShImjCN4VN3eSLlBEbve1QRQXM=
|
||||||
tags: true
|
skip_cleanup: true
|
||||||
condition: "$TRAVIS_OS_NAME == osx"
|
file: build/SolveSpace.dmg
|
||||||
|
on:
|
||||||
|
repo: solvespace/solvespace
|
||||||
|
tags: true
|
||||||
|
|
|
@ -4,12 +4,8 @@ if echo $TRAVIS_TAG | grep ^v; then BUILD_TYPE=RelWithDebInfo; else BUILD_TYPE=D
|
||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
# We build without the GUI until Travis updates to an Ubuntu version with GTK 3.16+.
|
|
||||||
cmake .. \
|
cmake .. \
|
||||||
-DCMAKE_C_COMPILER=gcc-5 \
|
|
||||||
-DCMAKE_CXX_COMPILER=g++-5 \
|
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DENABLE_GUI=OFF \
|
|
||||||
-DENABLE_SANITIZERS=ON
|
-DENABLE_SANITIZERS=ON
|
||||||
make VERBOSE=1
|
make VERBOSE=1
|
||||||
make test_solvespace
|
make test_solvespace
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#!/bin/sh -xe
|
#!/bin/sh -xe
|
||||||
|
|
||||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
|
||||||
sudo apt-get update -qq
|
sudo apt-get update -qq
|
||||||
|
|
||||||
sudo apt-get install -q -y \
|
sudo apt-get install -q -y \
|
||||||
cmake cmake-data libc6-dev libpng12-dev zlib1g-dev libjson0-dev libfontconfig1-dev \
|
zlib1g-dev libpng-dev libcairo2-dev libfreetype6-dev libjson-c-dev \
|
||||||
libgtkmm-3.0-dev libpangomm-1.4-dev libcairo2-dev libgl1-mesa-dev libglu-dev \
|
libfontconfig1-dev libgtkmm-3.0-dev libpangomm-1.4-dev libgl-dev \
|
||||||
libfreetype6-dev dpkg-dev gcc-5 g++-5 lcov
|
libgl-dev libglu-dev libspnav-dev
|
||||||
|
|
||||||
|
git submodule update --init extlib/libdxfrw extlib/flatbuffers extlib/q3d
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
|
|
||||||
brew update
|
brew update
|
||||||
brew install freetype cairo
|
brew install freetype cairo
|
||||||
|
git submodule update --init
|
||||||
|
|
|
@ -42,6 +42,8 @@ New constraint features:
|
||||||
constraints on line segments.
|
constraints on line segments.
|
||||||
* Automatic creation of constraints no longer happens if the constraint
|
* Automatic creation of constraints no longer happens if the constraint
|
||||||
would have been redundant with other ones.
|
would have been redundant with other ones.
|
||||||
|
* New option to open the constraint editor for newly created constraints
|
||||||
|
with a value.
|
||||||
|
|
||||||
New export/import features:
|
New export/import features:
|
||||||
* Three.js: allow configuring projection for exported model, and initially
|
* Three.js: allow configuring projection for exported model, and initially
|
||||||
|
|
|
@ -8,7 +8,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.2.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.2.0 FATAL_ERROR)
|
||||||
cmake_policy(VERSION 3.2.0)
|
cmake_policy(VERSION 3.11)
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
|
||||||
"${CMAKE_SOURCE_DIR}/cmake/")
|
"${CMAKE_SOURCE_DIR}/cmake/")
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
@ -49,6 +49,9 @@ set(OPENGL 3 CACHE STRING "OpenGL version to use (one of: 1 3)")
|
||||||
|
|
||||||
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
|
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
|
||||||
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
|
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
if("${CMAKE_GENERATOR}" STREQUAL "Xcode")
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_BINARY_DIR}/bin>)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT CMAKE_C_COMPILER_ID STREQUAL CMAKE_CXX_COMPILER_ID)
|
if(NOT CMAKE_C_COMPILER_ID STREQUAL CMAKE_CXX_COMPILER_ID)
|
||||||
message(FATAL_ERROR "C and C++ compilers should be supplied by the same vendor")
|
message(FATAL_ERROR "C and C++ compilers should be supplied by the same vendor")
|
||||||
|
@ -63,6 +66,15 @@ endif()
|
||||||
|
|
||||||
# common compiler flags
|
# common compiler flags
|
||||||
|
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
|
||||||
|
set(FILE_PREFIX_MAP "-ffile-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.")
|
||||||
|
check_cxx_compiler_flag("${FILE_PREFIX_MAP}" HAS_FILE_PREFIX_MAP)
|
||||||
|
if(HAS_FILE_PREFIX_MAP)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FILE_PREFIX_MAP}")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FILE_PREFIX_MAP}")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(MINGW)
|
if(MINGW)
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
||||||
|
|
|
@ -128,7 +128,6 @@ elseif(APPLE)
|
||||||
-fobjc-arc)
|
-fobjc-arc)
|
||||||
|
|
||||||
list(APPEND platform_SOURCES
|
list(APPEND platform_SOURCES
|
||||||
render/rendergl.cpp
|
|
||||||
platform/guimac.mm)
|
platform/guimac.mm)
|
||||||
else()
|
else()
|
||||||
list(APPEND platform_SOURCES
|
list(APPEND platform_SOURCES
|
||||||
|
|
|
@ -102,6 +102,11 @@ void TextWindow::ScreenChangeTurntableNav(int link, uint32_t v) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextWindow::ScreenChangeImmediatelyEditDimension(int link, uint32_t v) {
|
||||||
|
SS.immediatelyEditDimension = !SS.immediatelyEditDimension;
|
||||||
|
SS.GW.Invalidate(/*clearPersistent=*/true);
|
||||||
|
}
|
||||||
|
|
||||||
void TextWindow::ScreenChangeShowContourAreas(int link, uint32_t v) {
|
void TextWindow::ScreenChangeShowContourAreas(int link, uint32_t v) {
|
||||||
SS.showContourAreas = !SS.showContourAreas;
|
SS.showContourAreas = !SS.showContourAreas;
|
||||||
SS.GW.Invalidate();
|
SS.GW.Invalidate();
|
||||||
|
@ -342,6 +347,9 @@ void TextWindow::ShowConfiguration() {
|
||||||
SS.automaticLineConstraints ? CHECK_TRUE : CHECK_FALSE);
|
SS.automaticLineConstraints ? CHECK_TRUE : CHECK_FALSE);
|
||||||
Printf(false, " %Fd%f%Ll%s use turntable mouse navigation%E", &ScreenChangeTurntableNav,
|
Printf(false, " %Fd%f%Ll%s use turntable mouse navigation%E", &ScreenChangeTurntableNav,
|
||||||
SS.turntableNav ? CHECK_TRUE : CHECK_FALSE);
|
SS.turntableNav ? CHECK_TRUE : CHECK_FALSE);
|
||||||
|
Printf(false, " %Fd%f%Ll%s edit newly added dimensions%E",
|
||||||
|
&ScreenChangeImmediatelyEditDimension,
|
||||||
|
SS.immediatelyEditDimension ? CHECK_TRUE : CHECK_FALSE);
|
||||||
Printf(false, "");
|
Printf(false, "");
|
||||||
Printf(false, "%Ft autosave interval (in minutes)%E");
|
Printf(false, "%Ft autosave interval (in minutes)%E");
|
||||||
Printf(false, "%Ba %d %Fl%Ll%f[change]%E",
|
Printf(false, "%Ba %d %Fl%Ll%f[change]%E",
|
||||||
|
|
|
@ -196,6 +196,9 @@ void Constraint::MenuConstrain(Command id) {
|
||||||
c.valA = 0;
|
c.valA = 0;
|
||||||
c.ModifyToSatisfy();
|
c.ModifyToSatisfy();
|
||||||
AddConstraint(&c);
|
AddConstraint(&c);
|
||||||
|
if (SS.immediatelyEditDimension) {
|
||||||
|
SS.GW.EditConstraint(c.h);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,6 +610,9 @@ void Constraint::MenuConstrain(Command id) {
|
||||||
|
|
||||||
c.ModifyToSatisfy();
|
c.ModifyToSatisfy();
|
||||||
AddConstraint(&c);
|
AddConstraint(&c);
|
||||||
|
if (SS.immediatelyEditDimension) {
|
||||||
|
SS.GW.EditConstraint(c.h);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -845,7 +845,7 @@ void GraphicsWindow::Paint() {
|
||||||
|
|
||||||
canvas->SetLighting(lighting);
|
canvas->SetLighting(lighting);
|
||||||
canvas->SetCamera(camera);
|
canvas->SetCamera(camera);
|
||||||
canvas->NewFrame();
|
canvas->StartFrame();
|
||||||
Draw(canvas.get());
|
Draw(canvas.get());
|
||||||
canvas->FlushFrame();
|
canvas->FlushFrame();
|
||||||
|
|
||||||
|
@ -902,6 +902,7 @@ void GraphicsWindow::Paint() {
|
||||||
5, 5, renderTimeColor);
|
5, 5, renderTimeColor);
|
||||||
|
|
||||||
canvas->FlushFrame();
|
canvas->FlushFrame();
|
||||||
|
canvas->FinishFrame();
|
||||||
canvas->Clear();
|
canvas->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -480,11 +480,6 @@ public:
|
||||||
const T *cbegin() const { return begin(); }
|
const T *cbegin() const { return begin(); }
|
||||||
const T *cend() const { return end(); }
|
const T *cend() const { return end(); }
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
size_t CountIf(F &&predicate) const {
|
|
||||||
return std::count_if(begin(), end(), std::forward<F&&>(predicate));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearTags() {
|
void ClearTags() {
|
||||||
for(auto &elt : *this) { elt.tag = 0; }
|
for(auto &elt : *this) { elt.tag = 0; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,8 @@ bool Group::IsVisible() {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Group::GetNumConstraints() {
|
size_t Group::GetNumConstraints() {
|
||||||
return SK.constraint.CountIf([&](Constraint const & c) { return c.group == h; });
|
return std::count_if(SK.constraint.begin(), SK.constraint.end(),
|
||||||
|
[&](Constraint const &c) { return c.group == h; });
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector Group::ExtrusionGetVector() {
|
Vector Group::ExtrusionGetVector() {
|
||||||
|
|
|
@ -1068,8 +1068,9 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ImportDwgDxf(const Platform::Path &filename,
|
static void
|
||||||
std::function<bool(const std::string &data, DRW_Interface *intf)> read) {
|
ImportDwgDxf(const Platform::Path &filename,
|
||||||
|
const std::function<bool(const std::string &data, DRW_Interface *intf)> &read) {
|
||||||
std::string fileType = ToUpper(filename.Extension());
|
std::string fileType = ToUpper(filename.Extension());
|
||||||
|
|
||||||
std::string data;
|
std::string data;
|
||||||
|
|
|
@ -13,7 +13,7 @@ static System SYS;
|
||||||
|
|
||||||
static int IsInit = 0;
|
static int IsInit = 0;
|
||||||
|
|
||||||
void SolveSpace::Platform::FatalError(std::string message) {
|
void SolveSpace::Platform::FatalError(const std::string &message) {
|
||||||
fprintf(stderr, "%s", message.c_str());
|
fprintf(stderr, "%s", message.c_str());
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
128
src/mouse.cpp
128
src/mouse.cpp
|
@ -1339,73 +1339,77 @@ void GraphicsWindow::MouseLeftUp(double mx, double my, bool shiftDown, bool ctrl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphicsWindow::EditConstraint(hConstraint constraint) {
|
||||||
|
constraintBeingEdited = constraint;
|
||||||
|
ClearSuper();
|
||||||
|
|
||||||
|
Constraint *c = SK.GetConstraint(constraintBeingEdited);
|
||||||
|
if(!c->HasLabel()) {
|
||||||
|
// Not meaningful to edit a constraint without a dimension
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(c->reference) {
|
||||||
|
// Not meaningful to edit a reference dimension
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector p3 = c->GetLabelPos(GetCamera());
|
||||||
|
Point2d p2 = ProjectPoint(p3);
|
||||||
|
|
||||||
|
std::string editValue;
|
||||||
|
std::string editPlaceholder;
|
||||||
|
switch(c->type) {
|
||||||
|
case Constraint::Type::COMMENT:
|
||||||
|
editValue = c->comment;
|
||||||
|
editPlaceholder = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
double value = fabs(c->valA);
|
||||||
|
|
||||||
|
// If displayed as radius, also edit as radius.
|
||||||
|
if(c->type == Constraint::Type::DIAMETER && c->other)
|
||||||
|
value /= 2;
|
||||||
|
|
||||||
|
// Try showing value with default number of digits after decimal first.
|
||||||
|
if(c->type == Constraint::Type::LENGTH_RATIO) {
|
||||||
|
editValue = ssprintf("%.3f", value);
|
||||||
|
} else if(c->type == Constraint::Type::ANGLE) {
|
||||||
|
editValue = SS.DegreeToString(value);
|
||||||
|
} else {
|
||||||
|
editValue = SS.MmToString(value);
|
||||||
|
value /= SS.MmPerUnit();
|
||||||
|
}
|
||||||
|
// If that's not enough to represent it exactly, show the value with as many
|
||||||
|
// digits after decimal as required, up to 10.
|
||||||
|
int digits = 0;
|
||||||
|
while(fabs(std::stod(editValue) - value) > 1e-10) {
|
||||||
|
editValue = ssprintf("%.*f", digits, value);
|
||||||
|
digits++;
|
||||||
|
}
|
||||||
|
editPlaceholder = "10.000000";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double width, height;
|
||||||
|
window->GetContentSize(&width, &height);
|
||||||
|
hStyle hs = c->disp.style;
|
||||||
|
if(hs.v == 0) hs.v = Style::CONSTRAINT;
|
||||||
|
double capHeight = Style::TextHeight(hs);
|
||||||
|
double fontHeight = VectorFont::Builtin()->GetHeight(capHeight);
|
||||||
|
double editMinWidth = VectorFont::Builtin()->GetWidth(capHeight, editPlaceholder);
|
||||||
|
window->ShowEditor(p2.x + width / 2, height / 2 - p2.y,
|
||||||
|
fontHeight, editMinWidth,
|
||||||
|
/*isMonospace=*/false, editValue);
|
||||||
|
}
|
||||||
|
|
||||||
void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
|
void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
|
||||||
if(window->IsEditorVisible()) return;
|
if(window->IsEditorVisible()) return;
|
||||||
SS.TW.HideEditControl();
|
SS.TW.HideEditControl();
|
||||||
|
|
||||||
if(hover.constraint.v) {
|
if(hover.constraint.v) {
|
||||||
constraintBeingEdited = hover.constraint;
|
EditConstraint(hover.constraint);
|
||||||
ClearSuper();
|
|
||||||
|
|
||||||
Constraint *c = SK.GetConstraint(constraintBeingEdited);
|
|
||||||
if(!c->HasLabel()) {
|
|
||||||
// Not meaningful to edit a constraint without a dimension
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(c->reference) {
|
|
||||||
// Not meaningful to edit a reference dimension
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector p3 = c->GetLabelPos(GetCamera());
|
|
||||||
Point2d p2 = ProjectPoint(p3);
|
|
||||||
|
|
||||||
std::string editValue;
|
|
||||||
std::string editPlaceholder;
|
|
||||||
switch(c->type) {
|
|
||||||
case Constraint::Type::COMMENT:
|
|
||||||
editValue = c->comment;
|
|
||||||
editPlaceholder = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
double value = fabs(c->valA);
|
|
||||||
|
|
||||||
// If displayed as radius, also edit as radius.
|
|
||||||
if(c->type == Constraint::Type::DIAMETER && c->other)
|
|
||||||
value /= 2;
|
|
||||||
|
|
||||||
// Try showing value with default number of digits after decimal first.
|
|
||||||
if(c->type == Constraint::Type::LENGTH_RATIO) {
|
|
||||||
editValue = ssprintf("%.3f", value);
|
|
||||||
} else if(c->type == Constraint::Type::ANGLE) {
|
|
||||||
editValue = SS.DegreeToString(value);
|
|
||||||
} else {
|
|
||||||
editValue = SS.MmToString(value);
|
|
||||||
value /= SS.MmPerUnit();
|
|
||||||
}
|
|
||||||
// If that's not enough to represent it exactly, show the value with as many
|
|
||||||
// digits after decimal as required, up to 10.
|
|
||||||
int digits = 0;
|
|
||||||
while(fabs(std::stod(editValue) - value) > 1e-10) {
|
|
||||||
editValue = ssprintf("%.*f", digits, value);
|
|
||||||
digits++;
|
|
||||||
}
|
|
||||||
editPlaceholder = "10.000000";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double width, height;
|
|
||||||
window->GetContentSize(&width, &height);
|
|
||||||
hStyle hs = c->disp.style;
|
|
||||||
if(hs.v == 0) hs.v = Style::CONSTRAINT;
|
|
||||||
double capHeight = Style::TextHeight(hs);
|
|
||||||
double fontHeight = VectorFont::Builtin()->GetHeight(capHeight);
|
|
||||||
double editMinWidth = VectorFont::Builtin()->GetWidth(capHeight, editPlaceholder);
|
|
||||||
window->ShowEditor(p2.x + width / 2, height / 2 - p2.y,
|
|
||||||
fontHeight, editMinWidth,
|
|
||||||
/*isMonospace=*/false, editValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,9 +208,10 @@ static bool RunCommand(const std::vector<std::string> args) {
|
||||||
pixmapCanvas.SetCamera(camera);
|
pixmapCanvas.SetCamera(camera);
|
||||||
pixmapCanvas.Init();
|
pixmapCanvas.Init();
|
||||||
|
|
||||||
pixmapCanvas.NewFrame();
|
pixmapCanvas.StartFrame();
|
||||||
SS.GW.Draw(&pixmapCanvas);
|
SS.GW.Draw(&pixmapCanvas);
|
||||||
pixmapCanvas.FlushFrame();
|
pixmapCanvas.FlushFrame();
|
||||||
|
pixmapCanvas.FinishFrame();
|
||||||
pixmapCanvas.ReadFrame()->WritePng(output, /*flip=*/true);
|
pixmapCanvas.ReadFrame()->WritePng(output, /*flip=*/true);
|
||||||
|
|
||||||
pixmapCanvas.Clear();
|
pixmapCanvas.Clear();
|
||||||
|
|
|
@ -102,7 +102,7 @@ std::string AcceleratorDescription(const KeyboardEvent &accel);
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
__attribute__((noreturn))
|
__attribute__((noreturn))
|
||||||
#endif
|
#endif
|
||||||
void FatalError(std::string message);
|
void FatalError(const std::string &message);
|
||||||
|
|
||||||
// A native settings store.
|
// A native settings store.
|
||||||
class Settings {
|
class Settings {
|
||||||
|
|
|
@ -50,7 +50,7 @@ static std::string PrepareMnemonics(std::string label) {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string PrepareTitle(std::string title) {
|
static std::string PrepareTitle(const std::string &title) {
|
||||||
return title + " — SolveSpace";
|
return title + " — SolveSpace";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ static std::string PrepareTitle(std::string title) {
|
||||||
// Fatal errors
|
// Fatal errors
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void FatalError(std::string message) {
|
void FatalError(const std::string &message) {
|
||||||
fprintf(stderr, "%s", message.c_str());
|
fprintf(stderr, "%s", message.c_str());
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ crash_info_t crashAnnotation __attribute__((section("__DATA,__crash_info"))) = {
|
||||||
CRASH_VERSION, NULL, NULL, NULL, NULL, NULL, NULL
|
CRASH_VERSION, NULL, NULL, NULL, NULL, NULL, NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
void FatalError(std::string message) {
|
void FatalError(const std::string &message) {
|
||||||
crashAnnotation.message = message.c_str();
|
crashAnnotation.message = message.c_str();
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -225,9 +225,9 @@ public:
|
||||||
|
|
||||||
NSUInteger modifierMask = 0;
|
NSUInteger modifierMask = 0;
|
||||||
if(accel.shiftDown)
|
if(accel.shiftDown)
|
||||||
modifierMask |= NSShiftKeyMask;
|
modifierMask |= NSEventModifierFlagShift;
|
||||||
if(accel.controlDown)
|
if(accel.controlDown)
|
||||||
modifierMask |= NSCommandKeyMask;
|
modifierMask |= NSEventModifierFlagCommand;
|
||||||
nsMenuItem.keyEquivalentModifierMask = modifierMask;
|
nsMenuItem.keyEquivalentModifierMask = modifierMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetActive(bool active) override {
|
void SetActive(bool active) override {
|
||||||
nsMenuItem.state = active ? NSOnState : NSOffState;
|
nsMenuItem.state = active ? NSControlStateValueOn : NSControlStateValueOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetEnabled(bool enabled) override {
|
void SetEnabled(bool enabled) override {
|
||||||
|
@ -344,7 +344,7 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
||||||
// Cocoa NSView and NSWindow extensions
|
// Cocoa NSView and NSWindow extensions
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
@interface SSView : NSView
|
@interface SSView : NSOpenGLView
|
||||||
@property Platform::Window *receiver;
|
@property Platform::Window *receiver;
|
||||||
|
|
||||||
@property BOOL acceptsFirstResponder;
|
@property BOOL acceptsFirstResponder;
|
||||||
|
@ -362,8 +362,6 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
||||||
|
|
||||||
@implementation SSView
|
@implementation SSView
|
||||||
{
|
{
|
||||||
GlOffscreen offscreen;
|
|
||||||
NSOpenGLContext *glContext;
|
|
||||||
NSTrackingArea *trackingArea;
|
NSTrackingArea *trackingArea;
|
||||||
NSTextField *editor;
|
NSTextField *editor;
|
||||||
}
|
}
|
||||||
|
@ -371,17 +369,15 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
||||||
@synthesize acceptsFirstResponder;
|
@synthesize acceptsFirstResponder;
|
||||||
|
|
||||||
- (id)initWithFrame:(NSRect)frameRect {
|
- (id)initWithFrame:(NSRect)frameRect {
|
||||||
if(self = [super initWithFrame:frameRect]) {
|
NSOpenGLPixelFormatAttribute attrs[] = {
|
||||||
|
NSOpenGLPFAColorSize, 24,
|
||||||
|
NSOpenGLPFADepthSize, 24,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
|
||||||
|
if(self = [super initWithFrame:frameRect pixelFormat:pixelFormat]) {
|
||||||
|
self.wantsBestResolutionOpenGLSurface = YES;
|
||||||
self.wantsLayer = YES;
|
self.wantsLayer = YES;
|
||||||
|
|
||||||
NSOpenGLPixelFormatAttribute attrs[] = {
|
|
||||||
NSOpenGLPFAColorSize, 24,
|
|
||||||
NSOpenGLPFADepthSize, 24,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
|
|
||||||
glContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:NULL];
|
|
||||||
|
|
||||||
editor = [[NSTextField alloc] init];
|
editor = [[NSTextField alloc] init];
|
||||||
editor.editable = YES;
|
editor.editable = YES;
|
||||||
[[editor cell] setWraps:NO];
|
[[editor cell] setWraps:NO];
|
||||||
|
@ -394,7 +390,6 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
offscreen.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isFlipped {
|
- (BOOL)isFlipped {
|
||||||
|
@ -404,29 +399,11 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
||||||
@synthesize receiver;
|
@synthesize receiver;
|
||||||
|
|
||||||
- (void)drawRect:(NSRect)aRect {
|
- (void)drawRect:(NSRect)aRect {
|
||||||
[glContext makeCurrentContext];
|
[[self openGLContext] makeCurrentContext];
|
||||||
|
if(receiver->onRender) {
|
||||||
NSSize size = [self convertSizeToBacking:self.bounds.size];
|
receiver->onRender();
|
||||||
int width = (int)size.width,
|
}
|
||||||
height = (int)size.height;
|
[[self openGLContext] flushBuffer];
|
||||||
offscreen.Render(width, height, [&] {
|
|
||||||
if(receiver->onRender) {
|
|
||||||
receiver->onRender();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
CGDataProviderRef provider = CGDataProviderCreateWithData(
|
|
||||||
NULL, &offscreen.data[0], width * height * 4, NULL);
|
|
||||||
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
|
|
||||||
CGImageRef image = CGImageCreate(width, height, 8, 32,
|
|
||||||
width * 4, colorspace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
|
|
||||||
provider, NULL, true, kCGRenderingIntentDefault);
|
|
||||||
|
|
||||||
CGContextDrawImage((CGContextRef) [[NSGraphicsContext currentContext] graphicsPort],
|
|
||||||
[self bounds], image);
|
|
||||||
|
|
||||||
CGImageRelease(image);
|
|
||||||
CGDataProviderRelease(provider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)acceptsFirstMouse:(NSEvent *)event {
|
- (BOOL)acceptsFirstMouse:(NSEvent *)event {
|
||||||
|
@ -453,8 +430,8 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
||||||
event.y = self.bounds.size.height - nsPoint.y;
|
event.y = self.bounds.size.height - nsPoint.y;
|
||||||
|
|
||||||
NSUInteger nsFlags = [nsEvent modifierFlags];
|
NSUInteger nsFlags = [nsEvent modifierFlags];
|
||||||
if(nsFlags & NSShiftKeyMask) event.shiftDown = true;
|
if(nsFlags & NSEventModifierFlagShift) event.shiftDown = true;
|
||||||
if(nsFlags & NSCommandKeyMask) event.controlDown = true;
|
if(nsFlags & NSEventModifierFlagCommand) event.controlDown = true;
|
||||||
|
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
@ -587,9 +564,9 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
||||||
KeyboardEvent event = {};
|
KeyboardEvent event = {};
|
||||||
|
|
||||||
NSUInteger nsFlags = [nsEvent modifierFlags];
|
NSUInteger nsFlags = [nsEvent modifierFlags];
|
||||||
if(nsFlags & NSShiftKeyMask)
|
if(nsFlags & NSEventModifierFlagShift)
|
||||||
event.shiftDown = true;
|
event.shiftDown = true;
|
||||||
if(nsFlags & NSCommandKeyMask)
|
if(nsFlags & NSEventModifierFlagCommand)
|
||||||
event.controlDown = true;
|
event.controlDown = true;
|
||||||
|
|
||||||
unichar chr = 0;
|
unichar chr = 0;
|
||||||
|
@ -610,7 +587,7 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
||||||
- (void)keyDown:(NSEvent *)nsEvent {
|
- (void)keyDown:(NSEvent *)nsEvent {
|
||||||
using Platform::KeyboardEvent;
|
using Platform::KeyboardEvent;
|
||||||
|
|
||||||
if([NSEvent modifierFlags] & ~(NSShiftKeyMask|NSCommandKeyMask)) {
|
if([NSEvent modifierFlags] & ~(NSEventModifierFlagShift|NSEventModifierFlagCommand)) {
|
||||||
[super keyDown:nsEvent];
|
[super keyDown:nsEvent];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -629,7 +606,7 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
||||||
- (void)keyUp:(NSEvent *)nsEvent {
|
- (void)keyUp:(NSEvent *)nsEvent {
|
||||||
using Platform::KeyboardEvent;
|
using Platform::KeyboardEvent;
|
||||||
|
|
||||||
if([NSEvent modifierFlags] & ~(NSShiftKeyMask|NSCommandKeyMask)) {
|
if([NSEvent modifierFlags] & ~(NSEventModifierFlagShift|NSEventModifierFlagCommand)) {
|
||||||
[super keyUp:nsEvent];
|
[super keyUp:nsEvent];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -811,16 +788,16 @@ public:
|
||||||
switch(kind) {
|
switch(kind) {
|
||||||
case Window::Kind::TOPLEVEL:
|
case Window::Kind::TOPLEVEL:
|
||||||
nsWindow = [[NSWindow alloc] init];
|
nsWindow = [[NSWindow alloc] init];
|
||||||
nsWindow.styleMask = NSTitledWindowMask | NSResizableWindowMask |
|
nsWindow.styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable |
|
||||||
NSClosableWindowMask | NSMiniaturizableWindowMask;
|
NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
|
||||||
nsWindow.collectionBehavior = NSWindowCollectionBehaviorFullScreenPrimary;
|
nsWindow.collectionBehavior = NSWindowCollectionBehaviorFullScreenPrimary;
|
||||||
ssView.acceptsFirstResponder = YES;
|
ssView.acceptsFirstResponder = YES;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Window::Kind::TOOL:
|
case Window::Kind::TOOL:
|
||||||
NSPanel *nsPanel = [[NSPanel alloc] init];
|
NSPanel *nsPanel = [[NSPanel alloc] init];
|
||||||
nsPanel.styleMask = NSTitledWindowMask | NSResizableWindowMask |
|
nsPanel.styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable |
|
||||||
NSClosableWindowMask | NSUtilityWindowMask;
|
NSWindowStyleMaskClosable | NSWindowStyleMaskUtilityWindow;
|
||||||
[nsPanel standardWindowButton:NSWindowMiniaturizeButton].hidden = YES;
|
[nsPanel standardWindowButton:NSWindowMiniaturizeButton].hidden = YES;
|
||||||
[nsPanel standardWindowButton:NSWindowZoomButton].hidden = YES;
|
[nsPanel standardWindowButton:NSWindowZoomButton].hidden = YES;
|
||||||
nsPanel.floatingPanel = YES;
|
nsPanel.floatingPanel = YES;
|
||||||
|
@ -892,7 +869,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetContentSize(double *width, double *height) override {
|
void GetContentSize(double *width, double *height) override {
|
||||||
NSSize nsSize = [ssView frame].size;
|
NSSize nsSize = ssView.frame.size;
|
||||||
*width = nsSize.width;
|
*width = nsSize.width;
|
||||||
*height = nsSize.height;
|
*height = nsSize.height;
|
||||||
}
|
}
|
||||||
|
@ -975,9 +952,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetScrollbarPosition(double pos) override {
|
void SetScrollbarPosition(double pos) override {
|
||||||
if(pos > ssView.scrollerMax) {
|
if(pos > ssView.scrollerMax)
|
||||||
pos = ssView.scrollerMax;
|
pos = ssView.scrollerMax;
|
||||||
}
|
if(GetScrollbarPosition() == pos)
|
||||||
|
return;
|
||||||
[nsScroller setDoubleValue:(pos / (ssView.scrollerMax - ssView.scrollerMin))];
|
[nsScroller setDoubleValue:(pos / (ssView.scrollerMax - ssView.scrollerMin))];
|
||||||
if(onScrollbarAdjusted) {
|
if(onScrollbarAdjusted) {
|
||||||
onScrollbarAdjusted(pos);
|
onScrollbarAdjusted(pos);
|
||||||
|
@ -1128,17 +1106,17 @@ void Open3DConnexion() {
|
||||||
connexionClient = registerConnexionClient(connexionSignature, connexionName,
|
connexionClient = registerConnexionClient(connexionSignature, connexionName,
|
||||||
kConnexionClientModeTakeOver, kConnexionMaskButtons | kConnexionMaskAxis);
|
kConnexionClientModeTakeOver, kConnexionMaskButtons | kConnexionMaskAxis);
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyDownMask | NSFlagsChangedMask)
|
[NSEvent addLocalMonitorForEventsMatchingMask:(NSEventMaskKeyDown | NSEventMaskFlagsChanged)
|
||||||
handler:^(NSEvent *event) {
|
handler:^(NSEvent *event) {
|
||||||
connexionShiftIsDown = (event.modifierFlags & NSShiftKeyMask);
|
connexionShiftIsDown = (event.modifierFlags & NSEventModifierFlagShift);
|
||||||
connexionCommandIsDown = (event.modifierFlags & NSCommandKeyMask);
|
connexionCommandIsDown = (event.modifierFlags & NSEventModifierFlagCommand);
|
||||||
return event;
|
return event;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyUpMask | NSFlagsChangedMask)
|
[NSEvent addLocalMonitorForEventsMatchingMask:(NSEventMaskKeyUp | NSEventMaskFlagsChanged)
|
||||||
handler:^(NSEvent *event) {
|
handler:^(NSEvent *event) {
|
||||||
connexionShiftIsDown = (event.modifierFlags & NSShiftKeyMask);
|
connexionShiftIsDown = (event.modifierFlags & NSEventModifierFlagShift);
|
||||||
connexionCommandIsDown = (event.modifierFlags & NSCommandKeyMask);
|
connexionCommandIsDown = (event.modifierFlags & NSEventModifierFlagCommand);
|
||||||
return event;
|
return event;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
@ -1173,12 +1151,12 @@ public:
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case Type::INFORMATION:
|
case Type::INFORMATION:
|
||||||
case Type::QUESTION:
|
case Type::QUESTION:
|
||||||
nsAlert.alertStyle = NSInformationalAlertStyle;
|
nsAlert.alertStyle = NSAlertStyleInformational;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Type::WARNING:
|
case Type::WARNING:
|
||||||
case Type::ERROR:
|
case Type::ERROR:
|
||||||
nsAlert.alertStyle = NSWarningAlertStyle;
|
nsAlert.alertStyle = NSAlertStyleWarning;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1289,7 +1267,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RunModal() override {
|
bool RunModal() override {
|
||||||
if([nsPanel runModal] == NSFileHandlingPanelOKButton) {
|
if([nsPanel runModal] == NSModalResponseOK) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1431,6 +1409,9 @@ void OpenInBrowser(const std::string &url) {
|
||||||
|
|
||||||
@implementation SSApplicationDelegate
|
@implementation SSApplicationDelegate
|
||||||
- (IBAction)preferences:(id)sender {
|
- (IBAction)preferences:(id)sender {
|
||||||
|
if (!SS.GW.showTextWindow) {
|
||||||
|
SolveSpace::SS.GW.MenuView(SolveSpace::Command::SHOW_TEXT_WND);
|
||||||
|
}
|
||||||
SolveSpace::SS.TW.GoToScreen(SolveSpace::TextWindow::Screen::CONFIGURATION);
|
SolveSpace::SS.TW.GoToScreen(SolveSpace::TextWindow::Screen::CONFIGURATION);
|
||||||
SolveSpace::SS.ScheduleShowTW();
|
SolveSpace::SS.ScheduleShowTW();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Platform {
|
||||||
// Fatal errors
|
// Fatal errors
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void FatalError(std::string message) {
|
void FatalError(const std::string &message) {
|
||||||
fprintf(stderr, "%s", message.c_str());
|
fprintf(stderr, "%s", message.c_str());
|
||||||
|
|
||||||
#if !defined(LIBRARY) && defined(HAVE_BACKTRACE)
|
#if !defined(LIBRARY) && defined(HAVE_BACKTRACE)
|
||||||
|
|
|
@ -152,13 +152,12 @@ static int Clamp(int x, int a, int b) {
|
||||||
|
|
||||||
bool handlingFatalError = false;
|
bool handlingFatalError = false;
|
||||||
|
|
||||||
void FatalError(std::string message) {
|
void FatalError(const std::string &message) {
|
||||||
// Indicate that we're handling a fatal error, to avoid re-entering application code
|
// Indicate that we're handling a fatal error, to avoid re-entering application code
|
||||||
// and potentially crashing even harder.
|
// and potentially crashing even harder.
|
||||||
handlingFatalError = true;
|
handlingFatalError = true;
|
||||||
|
|
||||||
message += "\nGenerate debug report?";
|
switch(MessageBoxW(NULL, Platform::Widen(message + "\nGenerate debug report?").c_str(),
|
||||||
switch(MessageBoxW(NULL, Platform::Widen(message).c_str(),
|
|
||||||
L"Fatal error — SolveSpace",
|
L"Fatal error — SolveSpace",
|
||||||
MB_ICONERROR|MB_TASKMODAL|MB_SETFOREGROUND|MB_TOPMOST|
|
MB_ICONERROR|MB_TASKMODAL|MB_SETFOREGROUND|MB_TOPMOST|
|
||||||
MB_OKCANCEL|MB_DEFBUTTON2)) {
|
MB_OKCANCEL|MB_DEFBUTTON2)) {
|
||||||
|
@ -1355,7 +1354,11 @@ public:
|
||||||
SCROLLINFO si = {};
|
SCROLLINFO si = {};
|
||||||
si.cbSize = sizeof(si);
|
si.cbSize = sizeof(si);
|
||||||
si.fMask = SIF_POS;
|
si.fMask = SIF_POS;
|
||||||
si.nPos = (UINT)(pos * SCROLLBAR_UNIT);
|
sscheck(GetScrollInfo(hWindow, SB_VERT, &si));
|
||||||
|
if(si.nPos == (int)(pos * SCROLLBAR_UNIT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
si.nPos = (int)(pos * SCROLLBAR_UNIT);
|
||||||
sscheck(SetScrollInfo(hWindow, SB_VERT, &si, /*redraw=*/TRUE));
|
sscheck(SetScrollInfo(hWindow, SB_VERT, &si, /*redraw=*/TRUE));
|
||||||
|
|
||||||
// Windows won't synthesize a WM_VSCROLL for us here.
|
// Windows won't synthesize a WM_VSCROLL for us here.
|
||||||
|
|
|
@ -302,16 +302,10 @@ bool SEdgeList::AssemblePolygon(SPolygon *dest, SEdge *errorAt, bool keepDir) co
|
||||||
// but they are considered to cross if they are coincident and overlapping.
|
// but they are considered to cross if they are coincident and overlapping.
|
||||||
// If pi is not NULL, then a crossing is returned in that.
|
// If pi is not NULL, then a crossing is returned in that.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
int SEdgeList::AnyEdgeCrossings(Vector a, Vector b,
|
int SEdgeList::AnyEdgeCrossings(Vector a, Vector b, Vector *ppi, SPointList *spl) const {
|
||||||
Vector *ppi, SPointList *spl) const
|
auto cnt = std::count_if(l.begin(), l.end(),
|
||||||
{
|
[&](SEdge const &se) { return se.EdgeCrosses(a, b, ppi, spl); });
|
||||||
int cnt = 0;
|
return static_cast<int>(cnt);
|
||||||
for(const SEdge *se = l.First(); se; se = l.NextAfter(se)) {
|
|
||||||
if(se->EdgeCrosses(a, b, ppi, spl)) {
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -706,15 +700,10 @@ bool SPolygon::ContainsPoint(Vector p) const {
|
||||||
return (WindingNumberForPoint(p) % 2) == 1;
|
return (WindingNumberForPoint(p) % 2) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SPolygon::WindingNumberForPoint(Vector p) const {
|
size_t SPolygon::WindingNumberForPoint(Vector p) const {
|
||||||
int winding = 0;
|
auto winding = std::count_if(l.begin(), l.end(), [&](const SContour &sc) {
|
||||||
int i;
|
return sc.ContainsPointProjdToNormal(normal, p);
|
||||||
for(i = 0; i < l.n; i++) {
|
});
|
||||||
const SContour *sc = &(l[i]);
|
|
||||||
if(sc->ContainsPointProjdToNormal(normal, p)) {
|
|
||||||
winding++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return winding;
|
return winding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ public:
|
||||||
|
|
||||||
Vector ComputeNormal() const;
|
Vector ComputeNormal() const;
|
||||||
void AddEmptyContour();
|
void AddEmptyContour();
|
||||||
int WindingNumberForPoint(Vector p) const;
|
size_t WindingNumberForPoint(Vector p) const;
|
||||||
double SignedArea() const;
|
double SignedArea() const;
|
||||||
bool ContainsPoint(Vector p) const;
|
bool ContainsPoint(Vector p) const;
|
||||||
void MakeEdgesInto(SEdgeList *el) const;
|
void MakeEdgesInto(SEdgeList *el) const;
|
||||||
|
@ -184,7 +184,6 @@ public:
|
||||||
Vector Normal() const;
|
Vector Normal() const;
|
||||||
void FlipNormal();
|
void FlipNormal();
|
||||||
double MinAltitude() const;
|
double MinAltitude() const;
|
||||||
int WindingNumberForPoint(Vector p) const;
|
|
||||||
bool ContainsPoint(Vector p) const;
|
bool ContainsPoint(Vector p) const;
|
||||||
bool ContainsPointProjd(Vector n, Vector p) const;
|
bool ContainsPointProjd(Vector n, Vector p) const;
|
||||||
STriangle Transform(Vector o, Vector u, Vector v) const;
|
STriangle Transform(Vector o, Vector u, Vector v) const;
|
||||||
|
@ -403,11 +402,10 @@ public:
|
||||||
|
|
||||||
Vertex *AddVertex(const Vector &pos);
|
Vertex *AddVertex(const Vector &pos);
|
||||||
Edge *AddEdge(const Vector &p0, const Vector &p1, uint32_t kind, uintptr_t data = 0);
|
Edge *AddEdge(const Vector &p0, const Vector &p1, uint32_t kind, uintptr_t data = 0);
|
||||||
void Generate(
|
void Generate(std::function<void(Vertex *start, Vertex *next, Edge *edge)> const &startFunc,
|
||||||
std::function<void(Vertex *start, Vertex *next, Edge *edge)> startFunc,
|
std::function<void(Vertex *next, Edge *edge)> const &nextFunc,
|
||||||
std::function<void(Vertex *next, Edge *edge)> nextFunc,
|
std::function<void(Edge *)> const &aloneFunc,
|
||||||
std::function<void(Edge *)> aloneFunc,
|
std::function<void()> const &endFunc = []() {});
|
||||||
std::function<void()> endFunc = [](){});
|
|
||||||
|
|
||||||
void MakeFromEdges(const SEdgeList &sel);
|
void MakeFromEdges(const SEdgeList &sel);
|
||||||
void MakeFromOutlines(const SOutlineList &sol);
|
void MakeFromOutlines(const SOutlineList &sol);
|
||||||
|
|
|
@ -141,10 +141,9 @@ PolylineBuilder::Edge *PolylineBuilder::AddEdge(const Vector &p0, const Vector &
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolylineBuilder::Generate(
|
void PolylineBuilder::Generate(
|
||||||
std::function<void(Vertex *start, Vertex *next, Edge *edge)> startFunc,
|
std::function<void(Vertex *start, Vertex *next, Edge *edge)> const &startFunc,
|
||||||
std::function<void(Vertex *next, Edge *edge)> nextFunc,
|
std::function<void(Vertex *next, Edge *edge)> const &nextFunc,
|
||||||
std::function<void(Edge *alone)> aloneFunc,
|
std::function<void(Edge *alone)> const &aloneFunc, std::function<void()> const &endFunc) {
|
||||||
std::function<void()> endFunc) {
|
|
||||||
bool found;
|
bool found;
|
||||||
bool loop = false;
|
bool loop = false;
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -162,7 +162,7 @@ void Shader::Clear() {
|
||||||
glDeleteProgram(program);
|
glDeleteProgram(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::SetUniformMatrix(const char *name, double *md) {
|
void Shader::SetUniformMatrix(const char *name, const double *md) {
|
||||||
Enable();
|
Enable();
|
||||||
float mf[16];
|
float mf[16];
|
||||||
for(int i = 0; i < 16; i++) mf[i] = (float)md[i];
|
for(int i = 0; i < 16; i++) mf[i] = (float)md[i];
|
||||||
|
@ -388,8 +388,9 @@ GLuint Generate(const std::vector<double> &pattern) {
|
||||||
|
|
||||||
GLint size;
|
GLint size;
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
|
||||||
RgbaColor *textureData = new RgbaColor[size];
|
size /= 2;
|
||||||
|
|
||||||
|
RgbaColor *textureData = new RgbaColor[size];
|
||||||
int mipCount = (int)log2(size) + 1;
|
int mipCount = (int)log2(size) + 1;
|
||||||
for(int mip = 0; mip < mipCount; mip++) {
|
for(int mip = 0; mip < mipCount; mip++) {
|
||||||
int dashI = 0;
|
int dashI = 0;
|
||||||
|
@ -423,8 +424,8 @@ GLuint Generate(const std::vector<double> &pattern) {
|
||||||
textureData);
|
textureData);
|
||||||
size /= 2;
|
size /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete []textureData;
|
delete []textureData;
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,11 +622,11 @@ void EdgeRenderer::Draw(const SEdgeList &edges) {
|
||||||
Remove(handle);
|
Remove(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EdgeRenderer::SetModelview(double *matrix) {
|
void EdgeRenderer::SetModelview(const double *matrix) {
|
||||||
shader.SetUniformMatrix("modelview", matrix);
|
shader.SetUniformMatrix("modelview", matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EdgeRenderer::SetProjection(double *matrix) {
|
void EdgeRenderer::SetProjection(const double *matrix) {
|
||||||
shader.SetUniformMatrix("projection", matrix);
|
shader.SetUniformMatrix("projection", matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -833,11 +834,11 @@ void OutlineRenderer::Draw(const SOutlineList &outlines, Canvas::DrawOutlinesAs
|
||||||
Remove(handle);
|
Remove(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutlineRenderer::SetModelview(double *matrix) {
|
void OutlineRenderer::SetModelview(const double *matrix) {
|
||||||
shader.SetUniformMatrix("modelview", matrix);
|
shader.SetUniformMatrix("modelview", matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutlineRenderer::SetProjection(double *matrix) {
|
void OutlineRenderer::SetProjection(const double *matrix) {
|
||||||
shader.SetUniformMatrix("projection", matrix);
|
shader.SetUniformMatrix("projection", matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1037,14 +1038,14 @@ bool IndexedMeshRenderer::NeedsTexture() const {
|
||||||
selectedShader == &pointShader;
|
selectedShader == &pointShader;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexedMeshRenderer::SetModelview(double *matrix) {
|
void IndexedMeshRenderer::SetModelview(const double *matrix) {
|
||||||
colShader.SetUniformMatrix("modelview", matrix);
|
colShader.SetUniformMatrix("modelview", matrix);
|
||||||
texShader.SetUniformMatrix("modelview", matrix);
|
texShader.SetUniformMatrix("modelview", matrix);
|
||||||
texaShader.SetUniformMatrix("modelview", matrix);
|
texaShader.SetUniformMatrix("modelview", matrix);
|
||||||
pointShader.SetUniformMatrix("modelview", matrix);
|
pointShader.SetUniformMatrix("modelview", matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexedMeshRenderer::SetProjection(double *matrix) {
|
void IndexedMeshRenderer::SetProjection(const double *matrix) {
|
||||||
colShader.SetUniformMatrix("projection", matrix);
|
colShader.SetUniformMatrix("projection", matrix);
|
||||||
texShader.SetUniformMatrix("projection", matrix);
|
texShader.SetUniformMatrix("projection", matrix);
|
||||||
texaShader.SetUniformMatrix("projection", matrix);
|
texaShader.SetUniformMatrix("projection", matrix);
|
||||||
|
|
|
@ -74,7 +74,7 @@ public:
|
||||||
const std::vector<std::pair<GLuint, std::string>> &locations = {});
|
const std::vector<std::pair<GLuint, std::string>> &locations = {});
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
void SetUniformMatrix(const char *name, double *md);
|
void SetUniformMatrix(const char *name, const double *md);
|
||||||
void SetUniformVector(const char *name, const Vector &v);
|
void SetUniformVector(const char *name, const Vector &v);
|
||||||
void SetUniformVector(const char *name, const Vector4f &v);
|
void SetUniformVector(const char *name, const Vector4f &v);
|
||||||
void SetUniformColor(const char *name, RgbaColor c);
|
void SetUniformColor(const char *name, RgbaColor c);
|
||||||
|
@ -163,8 +163,8 @@ public:
|
||||||
void Draw(const Handle &handle);
|
void Draw(const Handle &handle);
|
||||||
void Draw(const SEdgeList &edges);
|
void Draw(const SEdgeList &edges);
|
||||||
|
|
||||||
void SetModelview(double *matrix);
|
void SetModelview(const double *matrix);
|
||||||
void SetProjection(double *matrix);
|
void SetProjection(const double *matrix);
|
||||||
void SetStroke(const Canvas::Stroke &stroke, double pixel);
|
void SetStroke(const Canvas::Stroke &stroke, double pixel);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -203,8 +203,8 @@ public:
|
||||||
void Draw(const Handle &handle, Canvas::DrawOutlinesAs mode);
|
void Draw(const Handle &handle, Canvas::DrawOutlinesAs mode);
|
||||||
void Draw(const SOutlineList &outlines, Canvas::DrawOutlinesAs mode);
|
void Draw(const SOutlineList &outlines, Canvas::DrawOutlinesAs mode);
|
||||||
|
|
||||||
void SetModelview(double *matrix);
|
void SetModelview(const double *matrix);
|
||||||
void SetProjection(double *matrix);
|
void SetProjection(const double *matrix);
|
||||||
void SetStroke(const Canvas::Stroke &stroke, double pixel);
|
void SetStroke(const Canvas::Stroke &stroke, double pixel);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -252,8 +252,8 @@ public:
|
||||||
void Draw(const Handle &handle);
|
void Draw(const Handle &handle);
|
||||||
void Draw(const SIndexedMesh &mesh);
|
void Draw(const SIndexedMesh &mesh);
|
||||||
|
|
||||||
void SetModelview(double *matrix);
|
void SetModelview(const double *matrix);
|
||||||
void SetProjection(double *matrix);
|
void SetProjection(const double *matrix);
|
||||||
|
|
||||||
bool NeedsTexture() const;
|
bool NeedsTexture() const;
|
||||||
|
|
||||||
|
|
|
@ -444,12 +444,11 @@ void ObjectPicker::DrawPixmap(std::shared_ptr<const Pixmap> pm,
|
||||||
DrawQuad(o, o.Plus(u), o.Plus(u).Plus(v), o.Plus(v), hcf);
|
DrawQuad(o, o.Plus(u), o.Plus(u).Plus(v), o.Plus(v), hcf);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ObjectPicker::Pick(std::function<void()> drawFn) {
|
bool ObjectPicker::Pick(const std::function<void()> &drawFn) {
|
||||||
minDistance = VERY_POSITIVE;
|
minDistance = VERY_POSITIVE;
|
||||||
maxZIndex = INT_MIN;
|
maxZIndex = INT_MIN;
|
||||||
|
|
||||||
drawFn();
|
drawFn();
|
||||||
return minDistance < selRadius;
|
return minDistance < selRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,8 +186,9 @@ public:
|
||||||
virtual void SetCamera(const Camera &camera) = 0;
|
virtual void SetCamera(const Camera &camera) = 0;
|
||||||
virtual void SetLighting(const Lighting &lighting) = 0;
|
virtual void SetLighting(const Lighting &lighting) = 0;
|
||||||
|
|
||||||
virtual void NewFrame() = 0;
|
virtual void StartFrame() = 0;
|
||||||
virtual void FlushFrame() = 0;
|
virtual void FlushFrame() = 0;
|
||||||
|
virtual void FinishFrame() = 0;
|
||||||
virtual std::shared_ptr<Pixmap> ReadFrame() = 0;
|
virtual std::shared_ptr<Pixmap> ReadFrame() = 0;
|
||||||
|
|
||||||
virtual void GetIdent(const char **vendor, const char **renderer, const char **version) = 0;
|
virtual void GetIdent(const char **vendor, const char **renderer, const char **version) = 0;
|
||||||
|
@ -260,7 +261,7 @@ public:
|
||||||
void DoQuad(const Vector &a, const Vector &b, const Vector &c, const Vector &d,
|
void DoQuad(const Vector &a, const Vector &b, const Vector &c, const Vector &d,
|
||||||
int zIndex, int comparePosition = 0);
|
int zIndex, int comparePosition = 0);
|
||||||
|
|
||||||
bool Pick(std::function<void()> drawFn);
|
bool Pick(const std::function<void()> &drawFn);
|
||||||
};
|
};
|
||||||
|
|
||||||
// A canvas that renders onto a 2d surface, performing z-index sorting, occlusion testing, etc,
|
// A canvas that renders onto a 2d surface, performing z-index sorting, occlusion testing, etc,
|
||||||
|
@ -342,8 +343,9 @@ public:
|
||||||
|
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
void NewFrame() override {}
|
void StartFrame() override {}
|
||||||
void FlushFrame() override;
|
void FlushFrame() override;
|
||||||
|
void FinishFrame() override {}
|
||||||
std::shared_ptr<Pixmap> ReadFrame() override;
|
std::shared_ptr<Pixmap> ReadFrame() override;
|
||||||
|
|
||||||
void GetIdent(const char **vendor, const char **renderer, const char **version) override;
|
void GetIdent(const char **vendor, const char **renderer, const char **version) override;
|
||||||
|
@ -373,22 +375,6 @@ public:
|
||||||
std::shared_ptr<Pixmap> ReadFrame() override;
|
std::shared_ptr<Pixmap> ReadFrame() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// 3d renderers
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// An offscreen renderer based on OpenGL framebuffers.
|
|
||||||
class GlOffscreen {
|
|
||||||
public:
|
|
||||||
unsigned int framebuffer = 0;
|
|
||||||
unsigned int colorRenderbuffer = 0;
|
|
||||||
unsigned int depthRenderbuffer = 0;
|
|
||||||
std::vector<uint8_t> data;
|
|
||||||
|
|
||||||
bool Render(int width, int height, std::function<void()> renderFn);
|
|
||||||
void Clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Factories
|
// Factories
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Offscreen rendering in OpenGL using EGL and framebuffer objects.
|
|
||||||
//
|
|
||||||
// Copyright 2015-2016 whitequark
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <OpenGL/gl.h>
|
|
||||||
#else
|
|
||||||
#define GL_GLEXT_PROTOTYPES
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "solvespace.h"
|
|
||||||
|
|
||||||
void GlOffscreen::Clear() {
|
|
||||||
glDeleteRenderbuffersEXT(1, &depthRenderbuffer);
|
|
||||||
glDeleteRenderbuffersEXT(1, &colorRenderbuffer);
|
|
||||||
glDeleteFramebuffersEXT(1, &framebuffer);
|
|
||||||
*this = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GlOffscreen::Render(int width, int height, std::function<void()> renderFn) {
|
|
||||||
data.resize(width * height * 4);
|
|
||||||
|
|
||||||
if(framebuffer == 0)
|
|
||||||
glGenFramebuffersEXT(1, &framebuffer);
|
|
||||||
if(colorRenderbuffer == 0)
|
|
||||||
glGenRenderbuffersEXT(1, &colorRenderbuffer);
|
|
||||||
if(depthRenderbuffer == 0)
|
|
||||||
glGenRenderbuffersEXT(1, &depthRenderbuffer);
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
|
|
||||||
|
|
||||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, colorRenderbuffer);
|
|
||||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, width, height);
|
|
||||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
|
||||||
GL_RENDERBUFFER_EXT, colorRenderbuffer);
|
|
||||||
|
|
||||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRenderbuffer);
|
|
||||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);
|
|
||||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
|
||||||
GL_RENDERBUFFER_EXT, depthRenderbuffer);
|
|
||||||
|
|
||||||
bool framebufferComplete =
|
|
||||||
glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT;
|
|
||||||
if(framebufferComplete) {
|
|
||||||
renderFn();
|
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
||||||
glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &data[0]);
|
|
||||||
#else
|
|
||||||
glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, &data[0]);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
||||||
|
|
||||||
return framebufferComplete;
|
|
||||||
}
|
|
|
@ -220,8 +220,9 @@ public:
|
||||||
void SetCamera(const Camera &camera) override;
|
void SetCamera(const Camera &camera) override;
|
||||||
void SetLighting(const Lighting &lighting) override;
|
void SetLighting(const Lighting &lighting) override;
|
||||||
|
|
||||||
void NewFrame() override;
|
void StartFrame() override;
|
||||||
void FlushFrame() override;
|
void FlushFrame() override;
|
||||||
|
void FinishFrame() override;
|
||||||
std::shared_ptr<Pixmap> ReadFrame() override;
|
std::shared_ptr<Pixmap> ReadFrame() override;
|
||||||
|
|
||||||
void GetIdent(const char **vendor, const char **renderer, const char **version) override;
|
void GetIdent(const char **vendor, const char **renderer, const char **version) override;
|
||||||
|
@ -751,7 +752,7 @@ void OpenGl1Renderer::UpdateProjection() {
|
||||||
glClear(GL_DEPTH_BUFFER_BIT);
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl1Renderer::NewFrame() {
|
void OpenGl1Renderer::StartFrame() {
|
||||||
glEnable(GL_NORMALIZE);
|
glEnable(GL_NORMALIZE);
|
||||||
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
@ -806,7 +807,12 @@ void OpenGl1Renderer::NewFrame() {
|
||||||
|
|
||||||
void OpenGl1Renderer::FlushFrame() {
|
void OpenGl1Renderer::FlushFrame() {
|
||||||
UnSelectPrimitive();
|
UnSelectPrimitive();
|
||||||
|
|
||||||
glFlush();
|
glFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGl1Renderer::FinishFrame() {
|
||||||
|
glFinish();
|
||||||
|
|
||||||
GLenum error = glGetError();
|
GLenum error = glGetError();
|
||||||
if(error != GL_NO_ERROR) {
|
if(error != GL_NO_ERROR) {
|
||||||
|
|
|
@ -87,6 +87,9 @@ public:
|
||||||
Fill *fill;
|
Fill *fill;
|
||||||
std::weak_ptr<const Pixmap> texture;
|
std::weak_ptr<const Pixmap> texture;
|
||||||
} current;
|
} current;
|
||||||
|
const char *vendor = "<uninitialized>";
|
||||||
|
const char *renderer = "<uninitialized>";
|
||||||
|
const char *version = "<uninitialized>";
|
||||||
|
|
||||||
// List-initialize current to work around MSVC bug 746973.
|
// List-initialize current to work around MSVC bug 746973.
|
||||||
OpenGl3Renderer() :
|
OpenGl3Renderer() :
|
||||||
|
@ -134,8 +137,9 @@ public:
|
||||||
void SetCamera(const Camera &c) override;
|
void SetCamera(const Camera &c) override;
|
||||||
void SetLighting(const Lighting &l) override;
|
void SetLighting(const Lighting &l) override;
|
||||||
|
|
||||||
void NewFrame() override;
|
void StartFrame() override;
|
||||||
void FlushFrame() override;
|
void FlushFrame() override;
|
||||||
|
void FinishFrame() override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
std::shared_ptr<Pixmap> ReadFrame() override;
|
std::shared_ptr<Pixmap> ReadFrame() override;
|
||||||
|
|
||||||
|
@ -439,6 +443,10 @@ void OpenGl3Renderer::Init() {
|
||||||
meshRenderer.Init();
|
meshRenderer.Init();
|
||||||
imeshRenderer.Init();
|
imeshRenderer.Init();
|
||||||
|
|
||||||
|
vendor = (const char *)glGetString(GL_VENDOR);
|
||||||
|
renderer = (const char *)glGetString(GL_RENDERER);
|
||||||
|
version = (const char *)glGetString(GL_VERSION);
|
||||||
|
|
||||||
#if !defined(HAVE_GLES) && !defined(__APPLE__)
|
#if !defined(HAVE_GLES) && !defined(__APPLE__)
|
||||||
GLuint array;
|
GLuint array;
|
||||||
glGenVertexArrays(1, &array);
|
glGenVertexArrays(1, &array);
|
||||||
|
@ -618,7 +626,7 @@ void OpenGl3Renderer::UpdateProjection() {
|
||||||
glClear(GL_DEPTH_BUFFER_BIT);
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl3Renderer::NewFrame() {
|
void OpenGl3Renderer::StartFrame() {
|
||||||
if(!initialized) {
|
if(!initialized) {
|
||||||
Init();
|
Init();
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
@ -667,6 +675,10 @@ void OpenGl3Renderer::FlushFrame() {
|
||||||
}
|
}
|
||||||
points.Clear();
|
points.Clear();
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGl3Renderer::FinishFrame() {
|
||||||
glFinish();
|
glFinish();
|
||||||
|
|
||||||
GLenum error = glGetError();
|
GLenum error = glGetError();
|
||||||
|
@ -691,9 +703,9 @@ std::shared_ptr<Pixmap> OpenGl3Renderer::ReadFrame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl3Renderer::GetIdent(const char **vendor, const char **renderer, const char **version) {
|
void OpenGl3Renderer::GetIdent(const char **vendor, const char **renderer, const char **version) {
|
||||||
*vendor = (const char *)glGetString(GL_VENDOR);
|
*vendor = this->vendor;
|
||||||
*renderer = (const char *)glGetString(GL_RENDERER);
|
*renderer = this->renderer;
|
||||||
*version = (const char *)glGetString(GL_VERSION);
|
*version = this->version;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl3Renderer::SetCamera(const Camera &c) {
|
void OpenGl3Renderer::SetCamera(const Camera &c) {
|
||||||
|
|
|
@ -918,7 +918,7 @@ Vector VectorFont::GetExtents(double forCapHeight, const std::string &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectorFont::Trace(double forCapHeight, Vector o, Vector u, Vector v, const std::string &str,
|
void VectorFont::Trace(double forCapHeight, Vector o, Vector u, Vector v, const std::string &str,
|
||||||
std::function<void(Vector, Vector)> traceEdge) {
|
const std::function<void(Vector, Vector)> &traceEdge) {
|
||||||
ssassert(!IsEmpty(), "Expected a loaded font");
|
ssassert(!IsEmpty(), "Expected a loaded font");
|
||||||
|
|
||||||
double scale = (forCapHeight / capHeight);
|
double scale = (forCapHeight / capHeight);
|
||||||
|
@ -945,7 +945,7 @@ void VectorFont::Trace(double forCapHeight, Vector o, Vector u, Vector v, const
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectorFont::Trace(double forCapHeight, Vector o, Vector u, Vector v, const std::string &str,
|
void VectorFont::Trace(double forCapHeight, Vector o, Vector u, Vector v, const std::string &str,
|
||||||
std::function<void(Vector, Vector)> traceEdge, const Camera &camera) {
|
const std::function<void(Vector, Vector)> &traceEdge, const Camera &camera) {
|
||||||
ssassert(!IsEmpty(), "Expected a loaded font");
|
ssassert(!IsEmpty(), "Expected a loaded font");
|
||||||
|
|
||||||
// Perform grid-fitting only when the text is parallel to the view plane.
|
// Perform grid-fitting only when the text is parallel to the view plane.
|
||||||
|
|
|
@ -103,9 +103,9 @@ public:
|
||||||
Vector GetExtents(double forCapHeight, const std::string &str);
|
Vector GetExtents(double forCapHeight, const std::string &str);
|
||||||
|
|
||||||
void Trace(double forCapHeight, Vector o, Vector u, Vector v, const std::string &str,
|
void Trace(double forCapHeight, Vector o, Vector u, Vector v, const std::string &str,
|
||||||
std::function<void(Vector, Vector)> traceEdge);
|
const std::function<void(Vector, Vector)> &traceEdge);
|
||||||
void Trace(double forCapHeight, Vector o, Vector u, Vector v, const std::string &str,
|
void Trace(double forCapHeight, Vector o, Vector u, Vector v, const std::string &str,
|
||||||
std::function<void(Vector, Vector)> traceEdge, const Camera &camera);
|
const std::function<void(Vector, Vector)> &traceEdge, const Camera &camera);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -72,6 +72,8 @@ void SolveSpaceUI::Init() {
|
||||||
drawBackFaces = settings->ThawBool("DrawBackFaces", true);
|
drawBackFaces = settings->ThawBool("DrawBackFaces", true);
|
||||||
// Use turntable mouse navigation
|
// Use turntable mouse navigation
|
||||||
turntableNav = settings->ThawBool("TurntableNav", false);
|
turntableNav = settings->ThawBool("TurntableNav", false);
|
||||||
|
// Immediately edit dimension
|
||||||
|
immediatelyEditDimension = settings->ThawBool("ImmediatelyEditDimension", false);
|
||||||
// Check that contours are closed and not self-intersecting
|
// Check that contours are closed and not self-intersecting
|
||||||
checkClosedContour = settings->ThawBool("CheckClosedContour", true);
|
checkClosedContour = settings->ThawBool("CheckClosedContour", true);
|
||||||
// Enable automatic constrains for lines
|
// Enable automatic constrains for lines
|
||||||
|
@ -251,6 +253,8 @@ void SolveSpaceUI::Exit() {
|
||||||
settings->FreezeBool("CheckClosedContour", checkClosedContour);
|
settings->FreezeBool("CheckClosedContour", checkClosedContour);
|
||||||
// Use turntable mouse navigation
|
// Use turntable mouse navigation
|
||||||
settings->FreezeBool("TurntableNav", turntableNav);
|
settings->FreezeBool("TurntableNav", turntableNav);
|
||||||
|
// Immediately edit dimensions
|
||||||
|
settings->FreezeBool("ImmediatelyEditDimension", immediatelyEditDimension);
|
||||||
// Enable automatic constrains for lines
|
// Enable automatic constrains for lines
|
||||||
settings->FreezeBool("AutomaticLineConstraints", automaticLineConstraints);
|
settings->FreezeBool("AutomaticLineConstraints", automaticLineConstraints);
|
||||||
// Export shaded triangles in a 2d view
|
// Export shaded triangles in a 2d view
|
||||||
|
@ -799,7 +803,6 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
|
||||||
Group *g = SK.GetGroup(SS.GW.activeGroup);
|
Group *g = SK.GetGroup(SS.GW.activeGroup);
|
||||||
SS.GW.GroupSelection();
|
SS.GW.GroupSelection();
|
||||||
auto const &gs = SS.GW.gs;
|
auto const &gs = SS.GW.gs;
|
||||||
double scale = SS.MmPerUnit();
|
|
||||||
|
|
||||||
if(gs.faces > 0) {
|
if(gs.faces > 0) {
|
||||||
std::vector<uint32_t> faces;
|
std::vector<uint32_t> faces;
|
||||||
|
|
|
@ -587,6 +587,7 @@ public:
|
||||||
bool showContourAreas;
|
bool showContourAreas;
|
||||||
bool checkClosedContour;
|
bool checkClosedContour;
|
||||||
bool turntableNav;
|
bool turntableNav;
|
||||||
|
bool immediatelyEditDimension;
|
||||||
bool automaticLineConstraints;
|
bool automaticLineConstraints;
|
||||||
bool showToolbar;
|
bool showToolbar;
|
||||||
Platform::Path screenshotFile;
|
Platform::Path screenshotFile;
|
||||||
|
|
|
@ -193,28 +193,24 @@ void SSurface::TrimFromEdgeList(SEdgeList *el, bool asUv) {
|
||||||
static bool KeepRegion(SSurface::CombineAs type, bool opA, SShell::Class shell, SShell::Class orig)
|
static bool KeepRegion(SSurface::CombineAs type, bool opA, SShell::Class shell, SShell::Class orig)
|
||||||
{
|
{
|
||||||
bool inShell = (shell == SShell::Class::INSIDE),
|
bool inShell = (shell == SShell::Class::INSIDE),
|
||||||
|
outSide = (shell == SShell::Class::OUTSIDE),
|
||||||
inSame = (shell == SShell::Class::COINC_SAME),
|
inSame = (shell == SShell::Class::COINC_SAME),
|
||||||
inOpp = (shell == SShell::Class::COINC_OPP),
|
|
||||||
inOrig = (orig == SShell::Class::INSIDE);
|
inOrig = (orig == SShell::Class::INSIDE);
|
||||||
|
|
||||||
bool inFace = inSame || inOpp;
|
|
||||||
|
|
||||||
// If these are correct, then they should be independent of inShell
|
|
||||||
// if inFace is true.
|
|
||||||
if(!inOrig) return false;
|
if(!inOrig) return false;
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case SSurface::CombineAs::UNION:
|
case SSurface::CombineAs::UNION:
|
||||||
if(opA) {
|
if(opA) {
|
||||||
return (!inShell && !inFace);
|
return outSide;
|
||||||
} else {
|
} else {
|
||||||
return (!inShell && !inFace) || inSame;
|
return outSide || inSame;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SSurface::CombineAs::DIFFERENCE:
|
case SSurface::CombineAs::DIFFERENCE:
|
||||||
if(opA) {
|
if(opA) {
|
||||||
return (!inShell && !inFace);
|
return outSide;
|
||||||
} else {
|
} else {
|
||||||
return (inShell && !inFace) || inSame;
|
return inShell || inSame;
|
||||||
}
|
}
|
||||||
|
|
||||||
default: ssassert(false, "Unexpected combine type");
|
default: ssassert(false, "Unexpected combine type");
|
||||||
|
|
|
@ -563,21 +563,24 @@ void TextWindow::Show() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(window) {
|
if(window) Resize();
|
||||||
double width, height;
|
}
|
||||||
window->GetContentSize(&width, &height);
|
|
||||||
|
|
||||||
halfRows = (int)height / (LINE_HEIGHT/2);
|
void TextWindow::Resize()
|
||||||
|
{
|
||||||
|
double width, height;
|
||||||
|
window->GetContentSize(&width, &height);
|
||||||
|
|
||||||
int bottom = top[rows-1] + 2;
|
halfRows = (int)height / (LINE_HEIGHT/2);
|
||||||
scrollPos = min(scrollPos, bottom - halfRows);
|
|
||||||
scrollPos = max(scrollPos, 0);
|
|
||||||
|
|
||||||
window->ConfigureScrollbar(0, top[rows - 1] + 1, halfRows);
|
int bottom = top[rows-1] + 2;
|
||||||
window->SetScrollbarPosition(scrollPos);
|
scrollPos = min(scrollPos, bottom - halfRows);
|
||||||
window->SetScrollbarVisible(top[rows - 1] + 1 > halfRows);
|
scrollPos = max(scrollPos, 0);
|
||||||
window->Invalidate();
|
|
||||||
}
|
window->ConfigureScrollbar(0, top[rows - 1] + 1, halfRows);
|
||||||
|
window->SetScrollbarPosition(scrollPos);
|
||||||
|
window->SetScrollbarVisible(top[rows - 1] + 1 > halfRows);
|
||||||
|
window->Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextWindow::DrawOrHitTestIcons(UiCanvas *uiCanvas, TextWindow::DrawOrHitHow how,
|
void TextWindow::DrawOrHitTestIcons(UiCanvas *uiCanvas, TextWindow::DrawOrHitHow how,
|
||||||
|
@ -909,6 +912,8 @@ void TextWindow::Paint() {
|
||||||
|
|
||||||
double width, height;
|
double width, height;
|
||||||
window->GetContentSize(&width, &height);
|
window->GetContentSize(&width, &height);
|
||||||
|
if(halfRows != (int)height / (LINE_HEIGHT/2))
|
||||||
|
Resize();
|
||||||
|
|
||||||
Camera camera = {};
|
Camera camera = {};
|
||||||
camera.width = width;
|
camera.width = width;
|
||||||
|
@ -924,7 +929,7 @@ void TextWindow::Paint() {
|
||||||
|
|
||||||
canvas->SetLighting(lighting);
|
canvas->SetLighting(lighting);
|
||||||
canvas->SetCamera(camera);
|
canvas->SetCamera(camera);
|
||||||
canvas->NewFrame();
|
canvas->StartFrame();
|
||||||
|
|
||||||
UiCanvas uiCanvas = {};
|
UiCanvas uiCanvas = {};
|
||||||
uiCanvas.canvas = canvas;
|
uiCanvas.canvas = canvas;
|
||||||
|
@ -1041,6 +1046,7 @@ void TextWindow::Paint() {
|
||||||
DrawOrHitTestColorPicker(&uiCanvas, PAINT, false, 0, 0);
|
DrawOrHitTestColorPicker(&uiCanvas, PAINT, false, 0, 0);
|
||||||
|
|
||||||
canvas->FlushFrame();
|
canvas->FlushFrame();
|
||||||
|
canvas->FinishFrame();
|
||||||
canvas->Clear();
|
canvas->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1123,8 +1129,10 @@ void TextWindow::MouseLeave() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextWindow::ScrollbarEvent(double newPos) {
|
void TextWindow::ScrollbarEvent(double newPos) {
|
||||||
if(window->IsEditorVisible())
|
if(window->IsEditorVisible()) {
|
||||||
|
window->SetScrollbarPosition(scrollPos);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int bottom = top[rows-1] + 2;
|
int bottom = top[rows-1] + 2;
|
||||||
newPos = min((int)newPos, bottom - halfRows);
|
newPos = min((int)newPos, bottom - halfRows);
|
||||||
|
|
64
src/ttf.cpp
64
src/ttf.cpp
|
@ -97,9 +97,9 @@ TtfFont *TtfFontList::LoadFont(const std::string &font)
|
||||||
if(tf != l.end()) {
|
if(tf != l.end()) {
|
||||||
if(tf->fontFace == NULL) {
|
if(tf->fontFace == NULL) {
|
||||||
if(tf->IsResource())
|
if(tf->IsResource())
|
||||||
tf->LoadFromResource(fontLibrary, /*nameOnly=*/false);
|
tf->LoadFromResource(fontLibrary, /*keepOpen=*/true);
|
||||||
else
|
else
|
||||||
tf->LoadFromFile(fontLibrary, /*nameOnly=*/false);
|
tf->LoadFromFile(fontLibrary, /*keepOpen=*/true);
|
||||||
}
|
}
|
||||||
return tf;
|
return tf;
|
||||||
} else {
|
} else {
|
||||||
|
@ -155,7 +155,7 @@ bool TtfFont::IsResource() const {
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Load a TrueType font into memory.
|
// Load a TrueType font into memory.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
bool TtfFont::LoadFromFile(FT_Library fontLibrary, bool nameOnly) {
|
bool TtfFont::LoadFromFile(FT_Library fontLibrary, bool keepOpen) {
|
||||||
ssassert(!IsResource(), "Cannot load a font provided by a resource as a file.");
|
ssassert(!IsResource(), "Cannot load a font provided by a resource as a file.");
|
||||||
|
|
||||||
FT_Open_Args args = {};
|
FT_Open_Args args = {};
|
||||||
|
@ -171,14 +171,14 @@ bool TtfFont::LoadFromFile(FT_Library fontLibrary, bool nameOnly) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExtractTTFData(nameOnly);
|
return ExtractTTFData(keepOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Load a TrueType from resource in memory. Implemented to load bundled fonts
|
// Load a TrueType from resource in memory. Implemented to load bundled fonts
|
||||||
// through theresource system.
|
// through theresource system.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
bool TtfFont::LoadFromResource(FT_Library fontLibrary, bool nameOnly) {
|
bool TtfFont::LoadFromResource(FT_Library fontLibrary, bool keepOpen) {
|
||||||
ssassert(IsResource(), "Font to be loaded as resource is not provided by a resource "
|
ssassert(IsResource(), "Font to be loaded as resource is not provided by a resource "
|
||||||
"or does not have the 'res://' prefix.");
|
"or does not have the 'res://' prefix.");
|
||||||
|
|
||||||
|
@ -196,13 +196,13 @@ bool TtfFont::LoadFromResource(FT_Library fontLibrary, bool nameOnly) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExtractTTFData(nameOnly);
|
return ExtractTTFData(keepOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Extract font information. We care about the font name and unit size.
|
// Extract font information. We care about the font name and unit size.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
bool TtfFont::ExtractTTFData(bool nameOnly) {
|
bool TtfFont::ExtractTTFData(bool keepOpen) {
|
||||||
if(int fterr = FT_Select_Charmap(fontFace, FT_ENCODING_UNICODE)) {
|
if(int fterr = FT_Select_Charmap(fontFace, FT_ENCODING_UNICODE)) {
|
||||||
dbp("freetype: loading unicode CMap for file '%s' failed: %s",
|
dbp("freetype: loading unicode CMap for file '%s' failed: %s",
|
||||||
fontFile.raw.c_str(), ft_error_string(fterr));
|
fontFile.raw.c_str(), ft_error_string(fterr));
|
||||||
|
@ -214,12 +214,6 @@ bool TtfFont::ExtractTTFData(bool nameOnly) {
|
||||||
name = std::string(fontFace->family_name) +
|
name = std::string(fontFace->family_name) +
|
||||||
" (" + std::string(fontFace->style_name) + ")";
|
" (" + std::string(fontFace->style_name) + ")";
|
||||||
|
|
||||||
if(nameOnly) {
|
|
||||||
FT_Done_Face(fontFace);
|
|
||||||
fontFace = NULL;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We always ask Freetype to give us a unit size character.
|
// We always ask Freetype to give us a unit size character.
|
||||||
// It uses fixed point; put the unit size somewhere in the middle of the dynamic
|
// It uses fixed point; put the unit size somewhere in the middle of the dynamic
|
||||||
// range of its 26.6 fixed point type, and adjust the factors so that the unit
|
// range of its 26.6 fixed point type, and adjust the factors so that the unit
|
||||||
|
@ -231,8 +225,8 @@ bool TtfFont::ExtractTTFData(bool nameOnly) {
|
||||||
sizeRequest.horiResolution = 128;
|
sizeRequest.horiResolution = 128;
|
||||||
sizeRequest.vertResolution = 128;
|
sizeRequest.vertResolution = 128;
|
||||||
if(int fterr = FT_Request_Size(fontFace, &sizeRequest)) {
|
if(int fterr = FT_Request_Size(fontFace, &sizeRequest)) {
|
||||||
dbp("freetype: cannot set character size: %s",
|
dbp("freetype: size request for file '%s' failed: %s",
|
||||||
ft_error_string(fterr));
|
fontFile.raw.c_str(), ft_error_string(fterr));
|
||||||
FT_Done_Face(fontFace);
|
FT_Done_Face(fontFace);
|
||||||
fontFace = NULL;
|
fontFace = NULL;
|
||||||
return false;
|
return false;
|
||||||
|
@ -241,16 +235,17 @@ bool TtfFont::ExtractTTFData(bool nameOnly) {
|
||||||
char chr = 'A';
|
char chr = 'A';
|
||||||
uint32_t gid = FT_Get_Char_Index(fontFace, 'A');
|
uint32_t gid = FT_Get_Char_Index(fontFace, 'A');
|
||||||
if (gid == 0) {
|
if (gid == 0) {
|
||||||
dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID",
|
dbp("freetype: CID-to-GID mapping for CID 0x%04x in file '%s' failed: %s; "
|
||||||
chr, ft_error_string(gid));
|
"using CID as GID",
|
||||||
|
chr, fontFile.raw.c_str(), ft_error_string(gid));
|
||||||
dbp("Assuming cap height is the same as requested height (this is likely wrong).");
|
dbp("Assuming cap height is the same as requested height (this is likely wrong).");
|
||||||
capHeight = (double)sizeRequest.height;
|
capHeight = (double)sizeRequest.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gid) {
|
if(gid) {
|
||||||
if(int fterr = FT_Load_Glyph(fontFace, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) {
|
if(int fterr = FT_Load_Glyph(fontFace, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) {
|
||||||
dbp("freetype: cannot load glyph for GID 0x%04x: %s",
|
dbp("freetype: cannot load glyph for GID 0x%04x in file '%s': %s",
|
||||||
gid, ft_error_string(fterr));
|
gid, fontFile.raw.c_str(), ft_error_string(fterr));
|
||||||
FT_Done_Face(fontFace);
|
FT_Done_Face(fontFace);
|
||||||
fontFace = NULL;
|
fontFace = NULL;
|
||||||
return false;
|
return false;
|
||||||
|
@ -261,6 +256,15 @@ bool TtfFont::ExtractTTFData(bool nameOnly) {
|
||||||
capHeight = (double)bbox.yMax;
|
capHeight = (double)bbox.yMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we just wanted to get the font's name and figure out if it's actually usable, close
|
||||||
|
// it now. If we don't do this, and there are a lot of fonts, we can bump into the file
|
||||||
|
// descriptor limit (especially on Windows), breaking all file operations.
|
||||||
|
if(!keepOpen) {
|
||||||
|
FT_Done_Face(fontFace);
|
||||||
|
fontFace = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,8 +347,9 @@ void TtfFont::PlotString(const std::string &str,
|
||||||
for(char32_t cid : ReadUTF8(str)) {
|
for(char32_t cid : ReadUTF8(str)) {
|
||||||
uint32_t gid = FT_Get_Char_Index(fontFace, cid);
|
uint32_t gid = FT_Get_Char_Index(fontFace, cid);
|
||||||
if (gid == 0) {
|
if (gid == 0) {
|
||||||
dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID",
|
dbp("freetype: CID-to-GID mapping for CID 0x%04x in file '%s' failed: %s; "
|
||||||
cid, ft_error_string(gid));
|
"using CID as GID",
|
||||||
|
cid, fontFile.raw.c_str(), ft_error_string(gid));
|
||||||
gid = cid;
|
gid = cid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,8 +362,8 @@ void TtfFont::PlotString(const std::string &str,
|
||||||
* ones, antialiasing mitigates this considerably though.
|
* ones, antialiasing mitigates this considerably though.
|
||||||
*/
|
*/
|
||||||
if(int fterr = FT_Load_Glyph(fontFace, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) {
|
if(int fterr = FT_Load_Glyph(fontFace, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) {
|
||||||
dbp("freetype: cannot load glyph for GID 0x%04x: %s",
|
dbp("freetype: cannot load glyph for GID 0x%04x in file '%s': %s",
|
||||||
gid, ft_error_string(fterr));
|
gid, fontFile.raw.c_str(), ft_error_string(fterr));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,8 +395,8 @@ void TtfFont::PlotString(const std::string &str,
|
||||||
data.factor = (float)(1.0 / capHeight);
|
data.factor = (float)(1.0 / capHeight);
|
||||||
data.bx = bx;
|
data.bx = bx;
|
||||||
if(int fterr = FT_Outline_Decompose(&fontFace->glyph->outline, &outlineFuncs, &data)) {
|
if(int fterr = FT_Outline_Decompose(&fontFace->glyph->outline, &outlineFuncs, &data)) {
|
||||||
dbp("freetype: bezier decomposition failed (gid %d): %s",
|
dbp("freetype: bezier decomposition failed for GID 0x%4x in file '%s': %s",
|
||||||
gid, ft_error_string(fterr));
|
gid, fontFile.raw.c_str(), ft_error_string(fterr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// And we're done, so advance our position by the requested advance
|
// And we're done, so advance our position by the requested advance
|
||||||
|
@ -408,13 +413,14 @@ double TtfFont::AspectRatio(const std::string &str) {
|
||||||
for(char32_t chr : ReadUTF8(str)) {
|
for(char32_t chr : ReadUTF8(str)) {
|
||||||
uint32_t gid = FT_Get_Char_Index(fontFace, chr);
|
uint32_t gid = FT_Get_Char_Index(fontFace, chr);
|
||||||
if (gid == 0) {
|
if (gid == 0) {
|
||||||
dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID",
|
dbp("freetype: CID-to-GID mapping for CID 0x%04x in file '%s' failed: %s; "
|
||||||
chr, ft_error_string(gid));
|
"using CID as GID",
|
||||||
|
chr, fontFile.raw.c_str(), ft_error_string(gid));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(int fterr = FT_Load_Glyph(fontFace, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) {
|
if(int fterr = FT_Load_Glyph(fontFace, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) {
|
||||||
dbp("freetype: cannot load glyph (GID 0x%04x): %s",
|
dbp("freetype: cannot load glyph for GID 0x%04x in file '%s': %s",
|
||||||
gid, ft_error_string(fterr));
|
gid, fontFile.raw.c_str(), ft_error_string(fterr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,14 +20,14 @@ public:
|
||||||
bool IsResource() const;
|
bool IsResource() const;
|
||||||
|
|
||||||
std::string FontFileBaseName() const;
|
std::string FontFileBaseName() const;
|
||||||
bool LoadFromFile(FT_LibraryRec_ *fontLibrary, bool nameOnly = true);
|
bool LoadFromFile(FT_LibraryRec_ *fontLibrary, bool keepOpen = false);
|
||||||
bool LoadFromResource(FT_LibraryRec_ *fontLibrary, bool nameOnly = true);
|
bool LoadFromResource(FT_LibraryRec_ *fontLibrary, bool keepOpen = false);
|
||||||
|
|
||||||
void PlotString(const std::string &str,
|
void PlotString(const std::string &str,
|
||||||
SBezierList *sbl, Vector origin, Vector u, Vector v);
|
SBezierList *sbl, Vector origin, Vector u, Vector v);
|
||||||
double AspectRatio(const std::string &str);
|
double AspectRatio(const std::string &str);
|
||||||
|
|
||||||
bool ExtractTTFData(bool nameOnly);
|
bool ExtractTTFData(bool keepOpen);
|
||||||
};
|
};
|
||||||
|
|
||||||
class TtfFontList {
|
class TtfFontList {
|
||||||
|
|
3
src/ui.h
3
src/ui.h
|
@ -253,6 +253,7 @@ public:
|
||||||
void ClearScreen();
|
void ClearScreen();
|
||||||
|
|
||||||
void Show();
|
void Show();
|
||||||
|
void Resize();
|
||||||
|
|
||||||
// State for the screen that we are showing in the text window.
|
// State for the screen that we are showing in the text window.
|
||||||
enum class Screen : uint32_t {
|
enum class Screen : uint32_t {
|
||||||
|
@ -429,6 +430,7 @@ public:
|
||||||
static void ScreenChangeShowContourAreas(int link, uint32_t v);
|
static void ScreenChangeShowContourAreas(int link, uint32_t v);
|
||||||
static void ScreenChangeCheckClosedContour(int link, uint32_t v);
|
static void ScreenChangeCheckClosedContour(int link, uint32_t v);
|
||||||
static void ScreenChangeTurntableNav(int link, uint32_t v);
|
static void ScreenChangeTurntableNav(int link, uint32_t v);
|
||||||
|
static void ScreenChangeImmediatelyEditDimension(int link, uint32_t v);
|
||||||
static void ScreenChangeAutomaticLineConstraints(int link, uint32_t v);
|
static void ScreenChangeAutomaticLineConstraints(int link, uint32_t v);
|
||||||
static void ScreenChangePwlCurves(int link, uint32_t v);
|
static void ScreenChangePwlCurves(int link, uint32_t v);
|
||||||
static void ScreenChangeCanvasSizeAuto(int link, uint32_t v);
|
static void ScreenChangeCanvasSizeAuto(int link, uint32_t v);
|
||||||
|
@ -689,6 +691,7 @@ public:
|
||||||
void RemoveConstraintsForPointBeingDeleted(hEntity hpt);
|
void RemoveConstraintsForPointBeingDeleted(hEntity hpt);
|
||||||
void FixConstraintsForRequestBeingDeleted(hRequest hr);
|
void FixConstraintsForRequestBeingDeleted(hRequest hr);
|
||||||
void FixConstraintsForPointBeingDeleted(hEntity hpt);
|
void FixConstraintsForPointBeingDeleted(hEntity hpt);
|
||||||
|
void EditConstraint(hConstraint constraint);
|
||||||
|
|
||||||
// A selected entity.
|
// A selected entity.
|
||||||
class Selection {
|
class Selection {
|
||||||
|
|
|
@ -255,9 +255,10 @@ bool Test::Helper::CheckRender(const char *file, int line, const char *reference
|
||||||
pixmapCanvas.SetCamera(camera);
|
pixmapCanvas.SetCamera(camera);
|
||||||
pixmapCanvas.Init();
|
pixmapCanvas.Init();
|
||||||
|
|
||||||
pixmapCanvas.NewFrame();
|
pixmapCanvas.StartFrame();
|
||||||
SS.GW.Draw(&pixmapCanvas);
|
SS.GW.Draw(&pixmapCanvas);
|
||||||
pixmapCanvas.FlushFrame();
|
pixmapCanvas.FlushFrame();
|
||||||
|
pixmapCanvas.FinishFrame();
|
||||||
std::shared_ptr<Pixmap> frame = pixmapCanvas.ReadFrame();
|
std::shared_ptr<Pixmap> frame = pixmapCanvas.ReadFrame();
|
||||||
|
|
||||||
pixmapCanvas.Clear();
|
pixmapCanvas.Clear();
|
||||||
|
|
Loading…
Reference in New Issue