commit
cfd630f4ac
31
.travis.yml
31
.travis.yml
|
@ -1,19 +1,23 @@
|
|||
language: c
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
sudo: required
|
||||
dist: trusty
|
||||
osx_image: xcode8.2
|
||||
install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./.travis/install-debian.sh; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./.travis/install-macos.sh; fi
|
||||
script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./.travis/build-debian.sh; fi
|
||||
git:
|
||||
submodules: false
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
name: "Debian"
|
||||
os: linux
|
||||
dist: bionic
|
||||
install: ./.travis/install-debian.sh
|
||||
script: ./.travis/build-debian.sh
|
||||
- stage: deploy
|
||||
name: "OSX"
|
||||
os: osx
|
||||
osx_image: xcode8.3
|
||||
install: ./.travis/install-macos.sh
|
||||
# the awk command is a workaround for https://github.com/travis-ci/travis-ci/issues/4704.
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./.travis/build-macos.sh | awk '/.{0,32}/ {print $0}'; fi
|
||||
script: ./.travis/build-macos.sh | awk '/.{0,32}/ {print $0}'
|
||||
deploy:
|
||||
- provider: releases
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: dDlkIawHcODlW9B/20/cQCtzeoocvs0hKuNngRKXKqzXLWTRq33oq/B7+39tAixWbmv6exTpijiKrRNFiSCW5Z4iwHLwaRD4XJznxw63e/Hus/dxg2Tvqx7XFpkCz8mT1Z+gZQE5YxAngeZPpI/sZbZtF1UO3yH5eLeeokZ15p26ZskQUPoYuzrTgTzYL3XfpG3F+20rNBawH1ycsCTVD/08/n31d2m3CrKAsbW7er92ek6w4fzKr7NW8WeXjrPJETVpw5fQg1Od3pRGW8dPQaJcvKQEogMp8Mm0ETYd0qigg89/giBz7QwOgmAWQ4dH+DfZH4Ojl//127QztBolMvyDMQBykWrtJoGcij05sT6K2IJr2FHeUBO12MAEdjiVvhQj3DtTzjPiZAHHDBSLWxLKWWhlhHE4pq7g1MQhqXkaAHI2BLNzwLmaowbMT0bECf9yfz6xx18h6XPQFX44oOktraobVALFlyHqeKa8zdcUt22LF6uAL1m5dxL0tny3eXCIPE4UH/RZgua/cHV9G3cUvKQa/QnFSLRhvWVSbGB+7YsHouBJcsUOOW1gmd5442XuC7mpppccRldh+GSxUk6TBJRAx7TeQ0ybDUaoco9MUqp2twv3KreR2+8Q12PDaAhfQVNEGdF3wTm1sShImjCN4VN3eSLlBEbve1QRQXM=
|
||||
skip_cleanup: true
|
||||
|
@ -21,4 +25,3 @@ deploy:
|
|||
on:
|
||||
repo: solvespace/solvespace
|
||||
tags: true
|
||||
condition: "$TRAVIS_OS_NAME == osx"
|
||||
|
|
|
@ -4,12 +4,8 @@ if echo $TRAVIS_TAG | grep ^v; then BUILD_TYPE=RelWithDebInfo; else BUILD_TYPE=D
|
|||
|
||||
mkdir build
|
||||
cd build
|
||||
# We build without the GUI until Travis updates to an Ubuntu version with GTK 3.16+.
|
||||
cmake .. \
|
||||
-DCMAKE_C_COMPILER=gcc-5 \
|
||||
-DCMAKE_CXX_COMPILER=g++-5 \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DENABLE_GUI=OFF \
|
||||
-DENABLE_SANITIZERS=ON
|
||||
make VERBOSE=1
|
||||
make test_solvespace
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#!/bin/sh -xe
|
||||
|
||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update -qq
|
||||
|
||||
sudo apt-get install -q -y \
|
||||
cmake cmake-data libc6-dev libpng12-dev zlib1g-dev libjson0-dev libfontconfig1-dev \
|
||||
libgtkmm-3.0-dev libpangomm-1.4-dev libcairo2-dev libgl1-mesa-dev libglu-dev \
|
||||
libfreetype6-dev dpkg-dev gcc-5 g++-5 lcov
|
||||
zlib1g-dev libpng-dev libcairo2-dev libfreetype6-dev libjson-c-dev \
|
||||
libfontconfig1-dev libgtkmm-3.0-dev libpangomm-1.4-dev libgl-dev \
|
||||
libgl-dev libglu-dev libspnav-dev
|
||||
|
||||
git submodule update --init extlib/libdxfrw extlib/flatbuffers extlib/q3d
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
|
||||
brew update
|
||||
brew install freetype cairo
|
||||
git submodule update --init
|
||||
|
|
|
@ -42,6 +42,8 @@ New constraint features:
|
|||
constraints on line segments.
|
||||
* Automatic creation of constraints no longer happens if the constraint
|
||||
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:
|
||||
* Three.js: allow configuring projection for exported model, and initially
|
||||
|
|
|
@ -8,7 +8,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
|||
endif()
|
||||
|
||||
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}
|
||||
"${CMAKE_SOURCE_DIR}/cmake/")
|
||||
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(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)
|
||||
message(FATAL_ERROR "C and C++ compilers should be supplied by the same vendor")
|
||||
|
@ -63,6 +66,15 @@ endif()
|
|||
|
||||
# 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)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
||||
|
|
|
@ -128,7 +128,6 @@ elseif(APPLE)
|
|||
-fobjc-arc)
|
||||
|
||||
list(APPEND platform_SOURCES
|
||||
render/rendergl.cpp
|
||||
platform/guimac.mm)
|
||||
else()
|
||||
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) {
|
||||
SS.showContourAreas = !SS.showContourAreas;
|
||||
SS.GW.Invalidate();
|
||||
|
@ -342,6 +347,9 @@ void TextWindow::ShowConfiguration() {
|
|||
SS.automaticLineConstraints ? CHECK_TRUE : CHECK_FALSE);
|
||||
Printf(false, " %Fd%f%Ll%s use turntable mouse navigation%E", &ScreenChangeTurntableNav,
|
||||
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, "%Ft autosave interval (in minutes)%E");
|
||||
Printf(false, "%Ba %d %Fl%Ll%f[change]%E",
|
||||
|
|
|
@ -196,6 +196,9 @@ void Constraint::MenuConstrain(Command id) {
|
|||
c.valA = 0;
|
||||
c.ModifyToSatisfy();
|
||||
AddConstraint(&c);
|
||||
if (SS.immediatelyEditDimension) {
|
||||
SS.GW.EditConstraint(c.h);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -607,6 +610,9 @@ void Constraint::MenuConstrain(Command id) {
|
|||
|
||||
c.ModifyToSatisfy();
|
||||
AddConstraint(&c);
|
||||
if (SS.immediatelyEditDimension) {
|
||||
SS.GW.EditConstraint(c.h);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -845,7 +845,7 @@ void GraphicsWindow::Paint() {
|
|||
|
||||
canvas->SetLighting(lighting);
|
||||
canvas->SetCamera(camera);
|
||||
canvas->NewFrame();
|
||||
canvas->StartFrame();
|
||||
Draw(canvas.get());
|
||||
canvas->FlushFrame();
|
||||
|
||||
|
@ -902,6 +902,7 @@ void GraphicsWindow::Paint() {
|
|||
5, 5, renderTimeColor);
|
||||
|
||||
canvas->FlushFrame();
|
||||
canvas->FinishFrame();
|
||||
canvas->Clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -480,11 +480,6 @@ public:
|
|||
const T *cbegin() const { return begin(); }
|
||||
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() {
|
||||
for(auto &elt : *this) { elt.tag = 0; }
|
||||
}
|
||||
|
|
|
@ -50,7 +50,8 @@ bool Group::IsVisible() {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -1068,8 +1068,9 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static void ImportDwgDxf(const Platform::Path &filename,
|
||||
std::function<bool(const std::string &data, DRW_Interface *intf)> read) {
|
||||
static void
|
||||
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 data;
|
||||
|
|
|
@ -13,7 +13,7 @@ static System SYS;
|
|||
|
||||
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());
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -1339,12 +1339,8 @@ void GraphicsWindow::MouseLeftUp(double mx, double my, bool shiftDown, bool ctrl
|
|||
}
|
||||
}
|
||||
|
||||
void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
|
||||
if(window->IsEditorVisible()) return;
|
||||
SS.TW.HideEditControl();
|
||||
|
||||
if(hover.constraint.v) {
|
||||
constraintBeingEdited = hover.constraint;
|
||||
void GraphicsWindow::EditConstraint(hConstraint constraint) {
|
||||
constraintBeingEdited = constraint;
|
||||
ClearSuper();
|
||||
|
||||
Constraint *c = SK.GetConstraint(constraintBeingEdited);
|
||||
|
@ -1407,6 +1403,14 @@ void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
|
|||
fontHeight, editMinWidth,
|
||||
/*isMonospace=*/false, editValue);
|
||||
}
|
||||
|
||||
void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
|
||||
if(window->IsEditorVisible()) return;
|
||||
SS.TW.HideEditControl();
|
||||
|
||||
if(hover.constraint.v) {
|
||||
EditConstraint(hover.constraint);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsWindow::EditControlDone(const std::string &s) {
|
||||
|
|
|
@ -208,9 +208,10 @@ static bool RunCommand(const std::vector<std::string> args) {
|
|||
pixmapCanvas.SetCamera(camera);
|
||||
pixmapCanvas.Init();
|
||||
|
||||
pixmapCanvas.NewFrame();
|
||||
pixmapCanvas.StartFrame();
|
||||
SS.GW.Draw(&pixmapCanvas);
|
||||
pixmapCanvas.FlushFrame();
|
||||
pixmapCanvas.FinishFrame();
|
||||
pixmapCanvas.ReadFrame()->WritePng(output, /*flip=*/true);
|
||||
|
||||
pixmapCanvas.Clear();
|
||||
|
|
|
@ -102,7 +102,7 @@ std::string AcceleratorDescription(const KeyboardEvent &accel);
|
|||
#if defined(__GNUC__)
|
||||
__attribute__((noreturn))
|
||||
#endif
|
||||
void FatalError(std::string message);
|
||||
void FatalError(const std::string &message);
|
||||
|
||||
// A native settings store.
|
||||
class Settings {
|
||||
|
|
|
@ -50,7 +50,7 @@ static std::string PrepareMnemonics(std::string label) {
|
|||
return label;
|
||||
}
|
||||
|
||||
static std::string PrepareTitle(std::string title) {
|
||||
static std::string PrepareTitle(const std::string &title) {
|
||||
return title + " — SolveSpace";
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ static std::string PrepareTitle(std::string title) {
|
|||
// Fatal errors
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FatalError(std::string message) {
|
||||
void FatalError(const std::string &message) {
|
||||
fprintf(stderr, "%s", message.c_str());
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ crash_info_t crashAnnotation __attribute__((section("__DATA,__crash_info"))) = {
|
|||
CRASH_VERSION, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
void FatalError(std::string message) {
|
||||
void FatalError(const std::string &message) {
|
||||
crashAnnotation.message = message.c_str();
|
||||
abort();
|
||||
}
|
||||
|
@ -225,9 +225,9 @@ public:
|
|||
|
||||
NSUInteger modifierMask = 0;
|
||||
if(accel.shiftDown)
|
||||
modifierMask |= NSShiftKeyMask;
|
||||
modifierMask |= NSEventModifierFlagShift;
|
||||
if(accel.controlDown)
|
||||
modifierMask |= NSCommandKeyMask;
|
||||
modifierMask |= NSEventModifierFlagCommand;
|
||||
nsMenuItem.keyEquivalentModifierMask = modifierMask;
|
||||
}
|
||||
|
||||
|
@ -236,7 +236,7 @@ public:
|
|||
}
|
||||
|
||||
void SetActive(bool active) override {
|
||||
nsMenuItem.state = active ? NSOnState : NSOffState;
|
||||
nsMenuItem.state = active ? NSControlStateValueOn : NSControlStateValueOff;
|
||||
}
|
||||
|
||||
void SetEnabled(bool enabled) override {
|
||||
|
@ -344,7 +344,7 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
|||
// Cocoa NSView and NSWindow extensions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@interface SSView : NSView
|
||||
@interface SSView : NSOpenGLView
|
||||
@property Platform::Window *receiver;
|
||||
|
||||
@property BOOL acceptsFirstResponder;
|
||||
|
@ -362,8 +362,6 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
|||
|
||||
@implementation SSView
|
||||
{
|
||||
GlOffscreen offscreen;
|
||||
NSOpenGLContext *glContext;
|
||||
NSTrackingArea *trackingArea;
|
||||
NSTextField *editor;
|
||||
}
|
||||
|
@ -371,17 +369,15 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
|||
@synthesize acceptsFirstResponder;
|
||||
|
||||
- (id)initWithFrame:(NSRect)frameRect {
|
||||
if(self = [super initWithFrame:frameRect]) {
|
||||
self.wantsLayer = YES;
|
||||
|
||||
NSOpenGLPixelFormatAttribute attrs[] = {
|
||||
NSOpenGLPFAColorSize, 24,
|
||||
NSOpenGLPFADepthSize, 24,
|
||||
0
|
||||
};
|
||||
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
|
||||
glContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:NULL];
|
||||
|
||||
if(self = [super initWithFrame:frameRect pixelFormat:pixelFormat]) {
|
||||
self.wantsBestResolutionOpenGLSurface = YES;
|
||||
self.wantsLayer = YES;
|
||||
editor = [[NSTextField alloc] init];
|
||||
editor.editable = YES;
|
||||
[[editor cell] setWraps:NO];
|
||||
|
@ -394,7 +390,6 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
|||
}
|
||||
|
||||
- (void)dealloc {
|
||||
offscreen.Clear();
|
||||
}
|
||||
|
||||
- (BOOL)isFlipped {
|
||||
|
@ -404,29 +399,11 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
|||
@synthesize receiver;
|
||||
|
||||
- (void)drawRect:(NSRect)aRect {
|
||||
[glContext makeCurrentContext];
|
||||
|
||||
NSSize size = [self convertSizeToBacking:self.bounds.size];
|
||||
int width = (int)size.width,
|
||||
height = (int)size.height;
|
||||
offscreen.Render(width, height, [&] {
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
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);
|
||||
[[self openGLContext] flushBuffer];
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstMouse:(NSEvent *)event {
|
||||
|
@ -453,8 +430,8 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
|||
event.y = self.bounds.size.height - nsPoint.y;
|
||||
|
||||
NSUInteger nsFlags = [nsEvent modifierFlags];
|
||||
if(nsFlags & NSShiftKeyMask) event.shiftDown = true;
|
||||
if(nsFlags & NSCommandKeyMask) event.controlDown = true;
|
||||
if(nsFlags & NSEventModifierFlagShift) event.shiftDown = true;
|
||||
if(nsFlags & NSEventModifierFlagCommand) event.controlDown = true;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
@ -587,9 +564,9 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
|||
KeyboardEvent event = {};
|
||||
|
||||
NSUInteger nsFlags = [nsEvent modifierFlags];
|
||||
if(nsFlags & NSShiftKeyMask)
|
||||
if(nsFlags & NSEventModifierFlagShift)
|
||||
event.shiftDown = true;
|
||||
if(nsFlags & NSCommandKeyMask)
|
||||
if(nsFlags & NSEventModifierFlagCommand)
|
||||
event.controlDown = true;
|
||||
|
||||
unichar chr = 0;
|
||||
|
@ -610,7 +587,7 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
|||
- (void)keyDown:(NSEvent *)nsEvent {
|
||||
using Platform::KeyboardEvent;
|
||||
|
||||
if([NSEvent modifierFlags] & ~(NSShiftKeyMask|NSCommandKeyMask)) {
|
||||
if([NSEvent modifierFlags] & ~(NSEventModifierFlagShift|NSEventModifierFlagCommand)) {
|
||||
[super keyDown:nsEvent];
|
||||
return;
|
||||
}
|
||||
|
@ -629,7 +606,7 @@ MenuBarRef GetOrCreateMainMenu(bool *unique) {
|
|||
- (void)keyUp:(NSEvent *)nsEvent {
|
||||
using Platform::KeyboardEvent;
|
||||
|
||||
if([NSEvent modifierFlags] & ~(NSShiftKeyMask|NSCommandKeyMask)) {
|
||||
if([NSEvent modifierFlags] & ~(NSEventModifierFlagShift|NSEventModifierFlagCommand)) {
|
||||
[super keyUp:nsEvent];
|
||||
return;
|
||||
}
|
||||
|
@ -811,16 +788,16 @@ public:
|
|||
switch(kind) {
|
||||
case Window::Kind::TOPLEVEL:
|
||||
nsWindow = [[NSWindow alloc] init];
|
||||
nsWindow.styleMask = NSTitledWindowMask | NSResizableWindowMask |
|
||||
NSClosableWindowMask | NSMiniaturizableWindowMask;
|
||||
nsWindow.styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable |
|
||||
NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
|
||||
nsWindow.collectionBehavior = NSWindowCollectionBehaviorFullScreenPrimary;
|
||||
ssView.acceptsFirstResponder = YES;
|
||||
break;
|
||||
|
||||
case Window::Kind::TOOL:
|
||||
NSPanel *nsPanel = [[NSPanel alloc] init];
|
||||
nsPanel.styleMask = NSTitledWindowMask | NSResizableWindowMask |
|
||||
NSClosableWindowMask | NSUtilityWindowMask;
|
||||
nsPanel.styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable |
|
||||
NSWindowStyleMaskClosable | NSWindowStyleMaskUtilityWindow;
|
||||
[nsPanel standardWindowButton:NSWindowMiniaturizeButton].hidden = YES;
|
||||
[nsPanel standardWindowButton:NSWindowZoomButton].hidden = YES;
|
||||
nsPanel.floatingPanel = YES;
|
||||
|
@ -892,7 +869,7 @@ public:
|
|||
}
|
||||
|
||||
void GetContentSize(double *width, double *height) override {
|
||||
NSSize nsSize = [ssView frame].size;
|
||||
NSSize nsSize = ssView.frame.size;
|
||||
*width = nsSize.width;
|
||||
*height = nsSize.height;
|
||||
}
|
||||
|
@ -975,9 +952,10 @@ public:
|
|||
}
|
||||
|
||||
void SetScrollbarPosition(double pos) override {
|
||||
if(pos > ssView.scrollerMax) {
|
||||
if(pos > ssView.scrollerMax)
|
||||
pos = ssView.scrollerMax;
|
||||
}
|
||||
if(GetScrollbarPosition() == pos)
|
||||
return;
|
||||
[nsScroller setDoubleValue:(pos / (ssView.scrollerMax - ssView.scrollerMin))];
|
||||
if(onScrollbarAdjusted) {
|
||||
onScrollbarAdjusted(pos);
|
||||
|
@ -1128,17 +1106,17 @@ void Open3DConnexion() {
|
|||
connexionClient = registerConnexionClient(connexionSignature, connexionName,
|
||||
kConnexionClientModeTakeOver, kConnexionMaskButtons | kConnexionMaskAxis);
|
||||
|
||||
[NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyDownMask | NSFlagsChangedMask)
|
||||
[NSEvent addLocalMonitorForEventsMatchingMask:(NSEventMaskKeyDown | NSEventMaskFlagsChanged)
|
||||
handler:^(NSEvent *event) {
|
||||
connexionShiftIsDown = (event.modifierFlags & NSShiftKeyMask);
|
||||
connexionCommandIsDown = (event.modifierFlags & NSCommandKeyMask);
|
||||
connexionShiftIsDown = (event.modifierFlags & NSEventModifierFlagShift);
|
||||
connexionCommandIsDown = (event.modifierFlags & NSEventModifierFlagCommand);
|
||||
return event;
|
||||
}];
|
||||
|
||||
[NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyUpMask | NSFlagsChangedMask)
|
||||
[NSEvent addLocalMonitorForEventsMatchingMask:(NSEventMaskKeyUp | NSEventMaskFlagsChanged)
|
||||
handler:^(NSEvent *event) {
|
||||
connexionShiftIsDown = (event.modifierFlags & NSShiftKeyMask);
|
||||
connexionCommandIsDown = (event.modifierFlags & NSCommandKeyMask);
|
||||
connexionShiftIsDown = (event.modifierFlags & NSEventModifierFlagShift);
|
||||
connexionCommandIsDown = (event.modifierFlags & NSEventModifierFlagCommand);
|
||||
return event;
|
||||
}];
|
||||
}
|
||||
|
@ -1173,12 +1151,12 @@ public:
|
|||
switch(type) {
|
||||
case Type::INFORMATION:
|
||||
case Type::QUESTION:
|
||||
nsAlert.alertStyle = NSInformationalAlertStyle;
|
||||
nsAlert.alertStyle = NSAlertStyleInformational;
|
||||
break;
|
||||
|
||||
case Type::WARNING:
|
||||
case Type::ERROR:
|
||||
nsAlert.alertStyle = NSWarningAlertStyle;
|
||||
nsAlert.alertStyle = NSAlertStyleWarning;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1289,7 +1267,7 @@ public:
|
|||
}
|
||||
|
||||
bool RunModal() override {
|
||||
if([nsPanel runModal] == NSFileHandlingPanelOKButton) {
|
||||
if([nsPanel runModal] == NSModalResponseOK) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -1431,6 +1409,9 @@ void OpenInBrowser(const std::string &url) {
|
|||
|
||||
@implementation SSApplicationDelegate
|
||||
- (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.ScheduleShowTW();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Platform {
|
|||
// Fatal errors
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FatalError(std::string message) {
|
||||
void FatalError(const std::string &message) {
|
||||
fprintf(stderr, "%s", message.c_str());
|
||||
|
||||
#if !defined(LIBRARY) && defined(HAVE_BACKTRACE)
|
||||
|
|
|
@ -152,13 +152,12 @@ static int Clamp(int x, int a, int b) {
|
|||
|
||||
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
|
||||
// and potentially crashing even harder.
|
||||
handlingFatalError = true;
|
||||
|
||||
message += "\nGenerate debug report?";
|
||||
switch(MessageBoxW(NULL, Platform::Widen(message).c_str(),
|
||||
switch(MessageBoxW(NULL, Platform::Widen(message + "\nGenerate debug report?").c_str(),
|
||||
L"Fatal error — SolveSpace",
|
||||
MB_ICONERROR|MB_TASKMODAL|MB_SETFOREGROUND|MB_TOPMOST|
|
||||
MB_OKCANCEL|MB_DEFBUTTON2)) {
|
||||
|
@ -1355,7 +1354,11 @@ public:
|
|||
SCROLLINFO si = {};
|
||||
si.cbSize = sizeof(si);
|
||||
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));
|
||||
|
||||
// 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.
|
||||
// If pi is not NULL, then a crossing is returned in that.
|
||||
//-----------------------------------------------------------------------------
|
||||
int SEdgeList::AnyEdgeCrossings(Vector a, Vector b,
|
||||
Vector *ppi, SPointList *spl) const
|
||||
{
|
||||
int cnt = 0;
|
||||
for(const SEdge *se = l.First(); se; se = l.NextAfter(se)) {
|
||||
if(se->EdgeCrosses(a, b, ppi, spl)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
int SEdgeList::AnyEdgeCrossings(Vector a, Vector b, Vector *ppi, SPointList *spl) const {
|
||||
auto cnt = std::count_if(l.begin(), l.end(),
|
||||
[&](SEdge const &se) { return se.EdgeCrosses(a, b, ppi, spl); });
|
||||
return static_cast<int>(cnt);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -706,15 +700,10 @@ bool SPolygon::ContainsPoint(Vector p) const {
|
|||
return (WindingNumberForPoint(p) % 2) == 1;
|
||||
}
|
||||
|
||||
int SPolygon::WindingNumberForPoint(Vector p) const {
|
||||
int winding = 0;
|
||||
int i;
|
||||
for(i = 0; i < l.n; i++) {
|
||||
const SContour *sc = &(l[i]);
|
||||
if(sc->ContainsPointProjdToNormal(normal, p)) {
|
||||
winding++;
|
||||
}
|
||||
}
|
||||
size_t SPolygon::WindingNumberForPoint(Vector p) const {
|
||||
auto winding = std::count_if(l.begin(), l.end(), [&](const SContour &sc) {
|
||||
return sc.ContainsPointProjdToNormal(normal, p);
|
||||
});
|
||||
return winding;
|
||||
}
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ public:
|
|||
|
||||
Vector ComputeNormal() const;
|
||||
void AddEmptyContour();
|
||||
int WindingNumberForPoint(Vector p) const;
|
||||
size_t WindingNumberForPoint(Vector p) const;
|
||||
double SignedArea() const;
|
||||
bool ContainsPoint(Vector p) const;
|
||||
void MakeEdgesInto(SEdgeList *el) const;
|
||||
|
@ -184,7 +184,6 @@ public:
|
|||
Vector Normal() const;
|
||||
void FlipNormal();
|
||||
double MinAltitude() const;
|
||||
int WindingNumberForPoint(Vector p) const;
|
||||
bool ContainsPoint(Vector p) const;
|
||||
bool ContainsPointProjd(Vector n, Vector p) const;
|
||||
STriangle Transform(Vector o, Vector u, Vector v) const;
|
||||
|
@ -403,11 +402,10 @@ public:
|
|||
|
||||
Vertex *AddVertex(const Vector &pos);
|
||||
Edge *AddEdge(const Vector &p0, const Vector &p1, uint32_t kind, uintptr_t data = 0);
|
||||
void Generate(
|
||||
std::function<void(Vertex *start, Vertex *next, Edge *edge)> startFunc,
|
||||
std::function<void(Vertex *next, Edge *edge)> nextFunc,
|
||||
std::function<void(Edge *)> aloneFunc,
|
||||
std::function<void()> endFunc = [](){});
|
||||
void Generate(std::function<void(Vertex *start, Vertex *next, Edge *edge)> const &startFunc,
|
||||
std::function<void(Vertex *next, Edge *edge)> const &nextFunc,
|
||||
std::function<void(Edge *)> const &aloneFunc,
|
||||
std::function<void()> const &endFunc = []() {});
|
||||
|
||||
void MakeFromEdges(const SEdgeList &sel);
|
||||
void MakeFromOutlines(const SOutlineList &sol);
|
||||
|
|
|
@ -141,10 +141,9 @@ PolylineBuilder::Edge *PolylineBuilder::AddEdge(const Vector &p0, const Vector &
|
|||
}
|
||||
|
||||
void PolylineBuilder::Generate(
|
||||
std::function<void(Vertex *start, Vertex *next, Edge *edge)> startFunc,
|
||||
std::function<void(Vertex *next, Edge *edge)> nextFunc,
|
||||
std::function<void(Edge *alone)> aloneFunc,
|
||||
std::function<void()> endFunc) {
|
||||
std::function<void(Vertex *start, Vertex *next, Edge *edge)> const &startFunc,
|
||||
std::function<void(Vertex *next, Edge *edge)> const &nextFunc,
|
||||
std::function<void(Edge *alone)> const &aloneFunc, std::function<void()> const &endFunc) {
|
||||
bool found;
|
||||
bool loop = false;
|
||||
do {
|
||||
|
|
|
@ -162,7 +162,7 @@ void Shader::Clear() {
|
|||
glDeleteProgram(program);
|
||||
}
|
||||
|
||||
void Shader::SetUniformMatrix(const char *name, double *md) {
|
||||
void Shader::SetUniformMatrix(const char *name, const double *md) {
|
||||
Enable();
|
||||
float mf[16];
|
||||
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;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
|
||||
RgbaColor *textureData = new RgbaColor[size];
|
||||
size /= 2;
|
||||
|
||||
RgbaColor *textureData = new RgbaColor[size];
|
||||
int mipCount = (int)log2(size) + 1;
|
||||
for(int mip = 0; mip < mipCount; mip++) {
|
||||
int dashI = 0;
|
||||
|
@ -423,8 +424,8 @@ GLuint Generate(const std::vector<double> &pattern) {
|
|||
textureData);
|
||||
size /= 2;
|
||||
}
|
||||
|
||||
delete []textureData;
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
@ -621,11 +622,11 @@ void EdgeRenderer::Draw(const SEdgeList &edges) {
|
|||
Remove(handle);
|
||||
}
|
||||
|
||||
void EdgeRenderer::SetModelview(double *matrix) {
|
||||
void EdgeRenderer::SetModelview(const double *matrix) {
|
||||
shader.SetUniformMatrix("modelview", matrix);
|
||||
}
|
||||
|
||||
void EdgeRenderer::SetProjection(double *matrix) {
|
||||
void EdgeRenderer::SetProjection(const double *matrix) {
|
||||
shader.SetUniformMatrix("projection", matrix);
|
||||
}
|
||||
|
||||
|
@ -833,11 +834,11 @@ void OutlineRenderer::Draw(const SOutlineList &outlines, Canvas::DrawOutlinesAs
|
|||
Remove(handle);
|
||||
}
|
||||
|
||||
void OutlineRenderer::SetModelview(double *matrix) {
|
||||
void OutlineRenderer::SetModelview(const double *matrix) {
|
||||
shader.SetUniformMatrix("modelview", matrix);
|
||||
}
|
||||
|
||||
void OutlineRenderer::SetProjection(double *matrix) {
|
||||
void OutlineRenderer::SetProjection(const double *matrix) {
|
||||
shader.SetUniformMatrix("projection", matrix);
|
||||
}
|
||||
|
||||
|
@ -1037,14 +1038,14 @@ bool IndexedMeshRenderer::NeedsTexture() const {
|
|||
selectedShader == &pointShader;
|
||||
}
|
||||
|
||||
void IndexedMeshRenderer::SetModelview(double *matrix) {
|
||||
void IndexedMeshRenderer::SetModelview(const double *matrix) {
|
||||
colShader.SetUniformMatrix("modelview", matrix);
|
||||
texShader.SetUniformMatrix("modelview", matrix);
|
||||
texaShader.SetUniformMatrix("modelview", matrix);
|
||||
pointShader.SetUniformMatrix("modelview", matrix);
|
||||
}
|
||||
|
||||
void IndexedMeshRenderer::SetProjection(double *matrix) {
|
||||
void IndexedMeshRenderer::SetProjection(const double *matrix) {
|
||||
colShader.SetUniformMatrix("projection", matrix);
|
||||
texShader.SetUniformMatrix("projection", matrix);
|
||||
texaShader.SetUniformMatrix("projection", matrix);
|
||||
|
|
|
@ -74,7 +74,7 @@ public:
|
|||
const std::vector<std::pair<GLuint, std::string>> &locations = {});
|
||||
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 Vector4f &v);
|
||||
void SetUniformColor(const char *name, RgbaColor c);
|
||||
|
@ -163,8 +163,8 @@ public:
|
|||
void Draw(const Handle &handle);
|
||||
void Draw(const SEdgeList &edges);
|
||||
|
||||
void SetModelview(double *matrix);
|
||||
void SetProjection(double *matrix);
|
||||
void SetModelview(const double *matrix);
|
||||
void SetProjection(const double *matrix);
|
||||
void SetStroke(const Canvas::Stroke &stroke, double pixel);
|
||||
};
|
||||
|
||||
|
@ -203,8 +203,8 @@ public:
|
|||
void Draw(const Handle &handle, Canvas::DrawOutlinesAs mode);
|
||||
void Draw(const SOutlineList &outlines, Canvas::DrawOutlinesAs mode);
|
||||
|
||||
void SetModelview(double *matrix);
|
||||
void SetProjection(double *matrix);
|
||||
void SetModelview(const double *matrix);
|
||||
void SetProjection(const double *matrix);
|
||||
void SetStroke(const Canvas::Stroke &stroke, double pixel);
|
||||
};
|
||||
|
||||
|
@ -252,8 +252,8 @@ public:
|
|||
void Draw(const Handle &handle);
|
||||
void Draw(const SIndexedMesh &mesh);
|
||||
|
||||
void SetModelview(double *matrix);
|
||||
void SetProjection(double *matrix);
|
||||
void SetModelview(const double *matrix);
|
||||
void SetProjection(const double *matrix);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool ObjectPicker::Pick(std::function<void()> drawFn) {
|
||||
bool ObjectPicker::Pick(const std::function<void()> &drawFn) {
|
||||
minDistance = VERY_POSITIVE;
|
||||
maxZIndex = INT_MIN;
|
||||
|
||||
drawFn();
|
||||
return minDistance < selRadius;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -186,8 +186,9 @@ public:
|
|||
virtual void SetCamera(const Camera &camera) = 0;
|
||||
virtual void SetLighting(const Lighting &lighting) = 0;
|
||||
|
||||
virtual void NewFrame() = 0;
|
||||
virtual void StartFrame() = 0;
|
||||
virtual void FlushFrame() = 0;
|
||||
virtual void FinishFrame() = 0;
|
||||
virtual std::shared_ptr<Pixmap> ReadFrame() = 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,
|
||||
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,
|
||||
|
@ -342,8 +343,9 @@ public:
|
|||
|
||||
void Clear() override;
|
||||
|
||||
void NewFrame() override {}
|
||||
void StartFrame() override {}
|
||||
void FlushFrame() override;
|
||||
void FinishFrame() override {}
|
||||
std::shared_ptr<Pixmap> ReadFrame() override;
|
||||
|
||||
void GetIdent(const char **vendor, const char **renderer, const char **version) override;
|
||||
|
@ -373,22 +375,6 @@ public:
|
|||
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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -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 SetLighting(const Lighting &lighting) override;
|
||||
|
||||
void NewFrame() override;
|
||||
void StartFrame() override;
|
||||
void FlushFrame() override;
|
||||
void FinishFrame() override;
|
||||
std::shared_ptr<Pixmap> ReadFrame() 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);
|
||||
}
|
||||
|
||||
void OpenGl1Renderer::NewFrame() {
|
||||
void OpenGl1Renderer::StartFrame() {
|
||||
glEnable(GL_NORMALIZE);
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
@ -806,7 +807,12 @@ void OpenGl1Renderer::NewFrame() {
|
|||
|
||||
void OpenGl1Renderer::FlushFrame() {
|
||||
UnSelectPrimitive();
|
||||
|
||||
glFlush();
|
||||
}
|
||||
|
||||
void OpenGl1Renderer::FinishFrame() {
|
||||
glFinish();
|
||||
|
||||
GLenum error = glGetError();
|
||||
if(error != GL_NO_ERROR) {
|
||||
|
|
|
@ -87,6 +87,9 @@ public:
|
|||
Fill *fill;
|
||||
std::weak_ptr<const Pixmap> texture;
|
||||
} current;
|
||||
const char *vendor = "<uninitialized>";
|
||||
const char *renderer = "<uninitialized>";
|
||||
const char *version = "<uninitialized>";
|
||||
|
||||
// List-initialize current to work around MSVC bug 746973.
|
||||
OpenGl3Renderer() :
|
||||
|
@ -134,8 +137,9 @@ public:
|
|||
void SetCamera(const Camera &c) override;
|
||||
void SetLighting(const Lighting &l) override;
|
||||
|
||||
void NewFrame() override;
|
||||
void StartFrame() override;
|
||||
void FlushFrame() override;
|
||||
void FinishFrame() override;
|
||||
void Clear() override;
|
||||
std::shared_ptr<Pixmap> ReadFrame() override;
|
||||
|
||||
|
@ -439,6 +443,10 @@ void OpenGl3Renderer::Init() {
|
|||
meshRenderer.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__)
|
||||
GLuint array;
|
||||
glGenVertexArrays(1, &array);
|
||||
|
@ -618,7 +626,7 @@ void OpenGl3Renderer::UpdateProjection() {
|
|||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void OpenGl3Renderer::NewFrame() {
|
||||
void OpenGl3Renderer::StartFrame() {
|
||||
if(!initialized) {
|
||||
Init();
|
||||
initialized = true;
|
||||
|
@ -667,6 +675,10 @@ void OpenGl3Renderer::FlushFrame() {
|
|||
}
|
||||
points.Clear();
|
||||
|
||||
glFlush();
|
||||
}
|
||||
|
||||
void OpenGl3Renderer::FinishFrame() {
|
||||
glFinish();
|
||||
|
||||
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) {
|
||||
*vendor = (const char *)glGetString(GL_VENDOR);
|
||||
*renderer = (const char *)glGetString(GL_RENDERER);
|
||||
*version = (const char *)glGetString(GL_VERSION);
|
||||
*vendor = this->vendor;
|
||||
*renderer = this->renderer;
|
||||
*version = this->version;
|
||||
}
|
||||
|
||||
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,
|
||||
std::function<void(Vector, Vector)> traceEdge) {
|
||||
const std::function<void(Vector, Vector)> &traceEdge) {
|
||||
ssassert(!IsEmpty(), "Expected a loaded font");
|
||||
|
||||
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,
|
||||
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");
|
||||
|
||||
// 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);
|
||||
|
||||
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,
|
||||
std::function<void(Vector, Vector)> traceEdge, const Camera &camera);
|
||||
const std::function<void(Vector, Vector)> &traceEdge, const Camera &camera);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -72,6 +72,8 @@ void SolveSpaceUI::Init() {
|
|||
drawBackFaces = settings->ThawBool("DrawBackFaces", true);
|
||||
// Use turntable mouse navigation
|
||||
turntableNav = settings->ThawBool("TurntableNav", false);
|
||||
// Immediately edit dimension
|
||||
immediatelyEditDimension = settings->ThawBool("ImmediatelyEditDimension", false);
|
||||
// Check that contours are closed and not self-intersecting
|
||||
checkClosedContour = settings->ThawBool("CheckClosedContour", true);
|
||||
// Enable automatic constrains for lines
|
||||
|
@ -251,6 +253,8 @@ void SolveSpaceUI::Exit() {
|
|||
settings->FreezeBool("CheckClosedContour", checkClosedContour);
|
||||
// Use turntable mouse navigation
|
||||
settings->FreezeBool("TurntableNav", turntableNav);
|
||||
// Immediately edit dimensions
|
||||
settings->FreezeBool("ImmediatelyEditDimension", immediatelyEditDimension);
|
||||
// Enable automatic constrains for lines
|
||||
settings->FreezeBool("AutomaticLineConstraints", automaticLineConstraints);
|
||||
// Export shaded triangles in a 2d view
|
||||
|
@ -799,7 +803,6 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
|
|||
Group *g = SK.GetGroup(SS.GW.activeGroup);
|
||||
SS.GW.GroupSelection();
|
||||
auto const &gs = SS.GW.gs;
|
||||
double scale = SS.MmPerUnit();
|
||||
|
||||
if(gs.faces > 0) {
|
||||
std::vector<uint32_t> faces;
|
||||
|
|
|
@ -587,6 +587,7 @@ public:
|
|||
bool showContourAreas;
|
||||
bool checkClosedContour;
|
||||
bool turntableNav;
|
||||
bool immediatelyEditDimension;
|
||||
bool automaticLineConstraints;
|
||||
bool showToolbar;
|
||||
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)
|
||||
{
|
||||
bool inShell = (shell == SShell::Class::INSIDE),
|
||||
outSide = (shell == SShell::Class::OUTSIDE),
|
||||
inSame = (shell == SShell::Class::COINC_SAME),
|
||||
inOpp = (shell == SShell::Class::COINC_OPP),
|
||||
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;
|
||||
switch(type) {
|
||||
case SSurface::CombineAs::UNION:
|
||||
if(opA) {
|
||||
return (!inShell && !inFace);
|
||||
return outSide;
|
||||
} else {
|
||||
return (!inShell && !inFace) || inSame;
|
||||
return outSide || inSame;
|
||||
}
|
||||
|
||||
case SSurface::CombineAs::DIFFERENCE:
|
||||
if(opA) {
|
||||
return (!inShell && !inFace);
|
||||
return outSide;
|
||||
} else {
|
||||
return (inShell && !inFace) || inSame;
|
||||
return inShell || inSame;
|
||||
}
|
||||
|
||||
default: ssassert(false, "Unexpected combine type");
|
||||
|
|
|
@ -563,7 +563,11 @@ void TextWindow::Show() {
|
|||
}
|
||||
}
|
||||
|
||||
if(window) {
|
||||
if(window) Resize();
|
||||
}
|
||||
|
||||
void TextWindow::Resize()
|
||||
{
|
||||
double width, height;
|
||||
window->GetContentSize(&width, &height);
|
||||
|
||||
|
@ -578,7 +582,6 @@ void TextWindow::Show() {
|
|||
window->SetScrollbarVisible(top[rows - 1] + 1 > halfRows);
|
||||
window->Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void TextWindow::DrawOrHitTestIcons(UiCanvas *uiCanvas, TextWindow::DrawOrHitHow how,
|
||||
double mx, double my)
|
||||
|
@ -909,6 +912,8 @@ void TextWindow::Paint() {
|
|||
|
||||
double width, height;
|
||||
window->GetContentSize(&width, &height);
|
||||
if(halfRows != (int)height / (LINE_HEIGHT/2))
|
||||
Resize();
|
||||
|
||||
Camera camera = {};
|
||||
camera.width = width;
|
||||
|
@ -924,7 +929,7 @@ void TextWindow::Paint() {
|
|||
|
||||
canvas->SetLighting(lighting);
|
||||
canvas->SetCamera(camera);
|
||||
canvas->NewFrame();
|
||||
canvas->StartFrame();
|
||||
|
||||
UiCanvas uiCanvas = {};
|
||||
uiCanvas.canvas = canvas;
|
||||
|
@ -1041,6 +1046,7 @@ void TextWindow::Paint() {
|
|||
DrawOrHitTestColorPicker(&uiCanvas, PAINT, false, 0, 0);
|
||||
|
||||
canvas->FlushFrame();
|
||||
canvas->FinishFrame();
|
||||
canvas->Clear();
|
||||
}
|
||||
|
||||
|
@ -1123,8 +1129,10 @@ void TextWindow::MouseLeave() {
|
|||
}
|
||||
|
||||
void TextWindow::ScrollbarEvent(double newPos) {
|
||||
if(window->IsEditorVisible())
|
||||
if(window->IsEditorVisible()) {
|
||||
window->SetScrollbarPosition(scrollPos);
|
||||
return;
|
||||
}
|
||||
|
||||
int bottom = top[rows-1] + 2;
|
||||
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->fontFace == NULL) {
|
||||
if(tf->IsResource())
|
||||
tf->LoadFromResource(fontLibrary, /*nameOnly=*/false);
|
||||
tf->LoadFromResource(fontLibrary, /*keepOpen=*/true);
|
||||
else
|
||||
tf->LoadFromFile(fontLibrary, /*nameOnly=*/false);
|
||||
tf->LoadFromFile(fontLibrary, /*keepOpen=*/true);
|
||||
}
|
||||
return tf;
|
||||
} else {
|
||||
|
@ -155,7 +155,7 @@ bool TtfFont::IsResource() const {
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.");
|
||||
|
||||
FT_Open_Args args = {};
|
||||
|
@ -171,14 +171,14 @@ bool TtfFont::LoadFromFile(FT_Library fontLibrary, bool nameOnly) {
|
|||
return false;
|
||||
}
|
||||
|
||||
return ExtractTTFData(nameOnly);
|
||||
return ExtractTTFData(keepOpen);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Load a TrueType from resource in memory. Implemented to load bundled fonts
|
||||
// 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 "
|
||||
"or does not have the 'res://' prefix.");
|
||||
|
||||
|
@ -196,13 +196,13 @@ bool TtfFont::LoadFromResource(FT_Library fontLibrary, bool nameOnly) {
|
|||
return false;
|
||||
}
|
||||
|
||||
return ExtractTTFData(nameOnly);
|
||||
return ExtractTTFData(keepOpen);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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)) {
|
||||
dbp("freetype: loading unicode CMap for file '%s' failed: %s",
|
||||
fontFile.raw.c_str(), ft_error_string(fterr));
|
||||
|
@ -214,12 +214,6 @@ bool TtfFont::ExtractTTFData(bool nameOnly) {
|
|||
name = std::string(fontFace->family_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.
|
||||
// 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
|
||||
|
@ -231,8 +225,8 @@ bool TtfFont::ExtractTTFData(bool nameOnly) {
|
|||
sizeRequest.horiResolution = 128;
|
||||
sizeRequest.vertResolution = 128;
|
||||
if(int fterr = FT_Request_Size(fontFace, &sizeRequest)) {
|
||||
dbp("freetype: cannot set character size: %s",
|
||||
ft_error_string(fterr));
|
||||
dbp("freetype: size request for file '%s' failed: %s",
|
||||
fontFile.raw.c_str(), ft_error_string(fterr));
|
||||
FT_Done_Face(fontFace);
|
||||
fontFace = NULL;
|
||||
return false;
|
||||
|
@ -241,16 +235,17 @@ bool TtfFont::ExtractTTFData(bool nameOnly) {
|
|||
char chr = 'A';
|
||||
uint32_t gid = FT_Get_Char_Index(fontFace, 'A');
|
||||
if (gid == 0) {
|
||||
dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID",
|
||||
chr, ft_error_string(gid));
|
||||
dbp("freetype: CID-to-GID mapping for CID 0x%04x in file '%s' failed: %s; "
|
||||
"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).");
|
||||
capHeight = (double)sizeRequest.height;
|
||||
}
|
||||
|
||||
if(gid) {
|
||||
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",
|
||||
gid, ft_error_string(fterr));
|
||||
dbp("freetype: cannot load glyph for GID 0x%04x in file '%s': %s",
|
||||
gid, fontFile.raw.c_str(), ft_error_string(fterr));
|
||||
FT_Done_Face(fontFace);
|
||||
fontFace = NULL;
|
||||
return false;
|
||||
|
@ -261,6 +256,15 @@ bool TtfFont::ExtractTTFData(bool nameOnly) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -343,8 +347,9 @@ void TtfFont::PlotString(const std::string &str,
|
|||
for(char32_t cid : ReadUTF8(str)) {
|
||||
uint32_t gid = FT_Get_Char_Index(fontFace, cid);
|
||||
if (gid == 0) {
|
||||
dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID",
|
||||
cid, ft_error_string(gid));
|
||||
dbp("freetype: CID-to-GID mapping for CID 0x%04x in file '%s' failed: %s; "
|
||||
"using CID as GID",
|
||||
cid, fontFile.raw.c_str(), ft_error_string(gid));
|
||||
gid = cid;
|
||||
}
|
||||
|
||||
|
@ -357,8 +362,8 @@ void TtfFont::PlotString(const std::string &str,
|
|||
* ones, antialiasing mitigates this considerably though.
|
||||
*/
|
||||
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",
|
||||
gid, ft_error_string(fterr));
|
||||
dbp("freetype: cannot load glyph for GID 0x%04x in file '%s': %s",
|
||||
gid, fontFile.raw.c_str(), ft_error_string(fterr));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -390,8 +395,8 @@ void TtfFont::PlotString(const std::string &str,
|
|||
data.factor = (float)(1.0 / capHeight);
|
||||
data.bx = bx;
|
||||
if(int fterr = FT_Outline_Decompose(&fontFace->glyph->outline, &outlineFuncs, &data)) {
|
||||
dbp("freetype: bezier decomposition failed (gid %d): %s",
|
||||
gid, ft_error_string(fterr));
|
||||
dbp("freetype: bezier decomposition failed for GID 0x%4x in file '%s': %s",
|
||||
gid, fontFile.raw.c_str(), ft_error_string(fterr));
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
uint32_t gid = FT_Get_Char_Index(fontFace, chr);
|
||||
if (gid == 0) {
|
||||
dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID",
|
||||
chr, ft_error_string(gid));
|
||||
dbp("freetype: CID-to-GID mapping for CID 0x%04x in file '%s' failed: %s; "
|
||||
"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)) {
|
||||
dbp("freetype: cannot load glyph (GID 0x%04x): %s",
|
||||
gid, ft_error_string(fterr));
|
||||
dbp("freetype: cannot load glyph for GID 0x%04x in file '%s': %s",
|
||||
gid, fontFile.raw.c_str(), ft_error_string(fterr));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,14 +20,14 @@ public:
|
|||
bool IsResource() const;
|
||||
|
||||
std::string FontFileBaseName() const;
|
||||
bool LoadFromFile(FT_LibraryRec_ *fontLibrary, bool nameOnly = true);
|
||||
bool LoadFromResource(FT_LibraryRec_ *fontLibrary, bool nameOnly = true);
|
||||
bool LoadFromFile(FT_LibraryRec_ *fontLibrary, bool keepOpen = false);
|
||||
bool LoadFromResource(FT_LibraryRec_ *fontLibrary, bool keepOpen = false);
|
||||
|
||||
void PlotString(const std::string &str,
|
||||
SBezierList *sbl, Vector origin, Vector u, Vector v);
|
||||
double AspectRatio(const std::string &str);
|
||||
|
||||
bool ExtractTTFData(bool nameOnly);
|
||||
bool ExtractTTFData(bool keepOpen);
|
||||
};
|
||||
|
||||
class TtfFontList {
|
||||
|
|
3
src/ui.h
3
src/ui.h
|
@ -253,6 +253,7 @@ public:
|
|||
void ClearScreen();
|
||||
|
||||
void Show();
|
||||
void Resize();
|
||||
|
||||
// State for the screen that we are showing in the text window.
|
||||
enum class Screen : uint32_t {
|
||||
|
@ -429,6 +430,7 @@ public:
|
|||
static void ScreenChangeShowContourAreas(int link, uint32_t v);
|
||||
static void ScreenChangeCheckClosedContour(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 ScreenChangePwlCurves(int link, uint32_t v);
|
||||
static void ScreenChangeCanvasSizeAuto(int link, uint32_t v);
|
||||
|
@ -689,6 +691,7 @@ public:
|
|||
void RemoveConstraintsForPointBeingDeleted(hEntity hpt);
|
||||
void FixConstraintsForRequestBeingDeleted(hRequest hr);
|
||||
void FixConstraintsForPointBeingDeleted(hEntity hpt);
|
||||
void EditConstraint(hConstraint constraint);
|
||||
|
||||
// A selected entity.
|
||||
class Selection {
|
||||
|
|
|
@ -255,9 +255,10 @@ bool Test::Helper::CheckRender(const char *file, int line, const char *reference
|
|||
pixmapCanvas.SetCamera(camera);
|
||||
pixmapCanvas.Init();
|
||||
|
||||
pixmapCanvas.NewFrame();
|
||||
pixmapCanvas.StartFrame();
|
||||
SS.GW.Draw(&pixmapCanvas);
|
||||
pixmapCanvas.FlushFrame();
|
||||
pixmapCanvas.FinishFrame();
|
||||
std::shared_ptr<Pixmap> frame = pixmapCanvas.ReadFrame();
|
||||
|
||||
pixmapCanvas.Clear();
|
||||
|
|
Loading…
Reference in New Issue