Implement OS X port.

pull/3/head
whitequark 2015-03-24 09:45:53 +03:00
parent 5d7a5bf3a7
commit 95ab80d0ee
16 changed files with 1420 additions and 40 deletions

View File

@ -72,7 +72,10 @@ if(WIN32)
"${CMAKE_SOURCE_DIR}/extlib/si") "${CMAKE_SOURCE_DIR}/extlib/si")
set(SPACEWARE_LIBRARIES set(SPACEWARE_LIBRARIES
"${CMAKE_SOURCE_DIR}/extlib/si/siapp.lib") "${CMAKE_SOURCE_DIR}/extlib/si/siapp.lib")
else() elseif(APPLE)
find_package(PNG REQUIRED)
find_library(APPKIT_LIBRARY AppKit REQUIRED)
else() # Linux and compatible systems
find_package(PNG REQUIRED) find_package(PNG REQUIRED)
find_package(SpaceWare) find_package(SpaceWare)

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>solvespace</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>SolveSpace</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleVersion</key>
<string>${solvespace_VERSION_MAJOR}.${solvespace_VERSION_MINOR}</string>
<key>CFBundleShortVersionString</key>
<string>${solvespace_VERSION_MAJOR}.${solvespace_VERSION_MINOR}</string>
<key>NSHumanReadableCopyright</key>
<string>© 2008-2015 Jonathan Westhues and other authors</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>slvs</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>AppIcon.icns</string>
<key>CFBundleTypeName</key>
<string>SolveSpace sketch</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>slvs</string>
</array>
<key>CFBundleTypeRole</key>
<string>Editor</string>
</dict>
</array>
</dict>
</plist>

View File

@ -129,6 +129,27 @@ if(WIN32)
win32/freeze.cpp win32/freeze.cpp
win32/w32main.cpp win32/w32main.cpp
win32/resource.rc) win32/resource.rc)
elseif(APPLE)
add_definitions(
-mmacosx-version-min=10.6
-fobjc-arc)
set(platform_SOURCES
cocoa/cocoamain.mm
unix/gloffscreen.cpp)
set(platform_XIBS
cocoa/MainMenu.xib
cocoa/SaveFormatAccessory.xib)
set(platform_ICONS
cocoa/AppIcon.iconset)
set(platform_RESOURCES
unix/solvespace-48x48.png)
set(platform_LIBRARIES
${APPKIT_LIBRARY})
elseif(HAVE_FLTK) elseif(HAVE_FLTK)
include_directories(${FLTK_INCLUDE_DIR}) include_directories(${FLTK_INCLUDE_DIR})
@ -168,6 +189,52 @@ elseif(HAVE_GTK)
${GLEW_LIBRARIES}) ${GLEW_LIBRARIES})
endif() endif()
set(platform_BUNDLED_RESOURCES)
foreach(xib ${platform_XIBS})
get_filename_component(nib ${xib} NAME_WE)
set(source ${CMAKE_CURRENT_SOURCE_DIR}/${xib})
set(target ${CMAKE_CURRENT_BINARY_DIR}/solvespace.app/Contents/Resources/${nib}.nib)
list(APPEND platform_BUNDLED_RESOURCES ${target})
add_custom_command(
OUTPUT ${target}
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/solvespace.app/Contents/Resources
COMMAND ibtool --errors --warnings --notices
--output-format human-readable-text --compile
${target} ${source}
COMMENT "Building Interface Builder file ${xib}"
DEPENDS ${xib})
endforeach()
foreach(icon ${platform_ICONS})
get_filename_component(name ${icon} NAME_WE)
set(source ${CMAKE_CURRENT_SOURCE_DIR}/${icon})
set(target ${CMAKE_CURRENT_BINARY_DIR}/solvespace.app/Contents/Resources/${name}.icns)
list(APPEND platform_BUNDLED_RESOURCES ${target})
add_custom_command(
OUTPUT ${target}
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/solvespace.app/Contents/Resources
COMMAND iconutil -c icns -o ${target} ${source}
COMMENT "Building icon set ${icon}"
DEPENDS ${source})
endforeach()
foreach(res ${platform_RESOURCES})
get_filename_component(name ${res} NAME)
set(source ${CMAKE_CURRENT_SOURCE_DIR}/${res})
set(target ${CMAKE_CURRENT_BINARY_DIR}/solvespace.app/Contents/Resources/${name})
list(APPEND platform_BUNDLED_RESOURCES ${target})
add_custom_command(
OUTPUT ${target}
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/solvespace.app/Contents/Resources
COMMAND ${CMAKE_COMMAND} -E copy ${source} ${target}
COMMENT "Copying resource file ${res}"
DEPENDS ${res})
endforeach()
# solvespace executable # solvespace executable
set(solvespace_HEADERS set(solvespace_HEADERS
@ -226,12 +293,13 @@ set(solvespace_SOURCES
srf/surfinter.cpp srf/surfinter.cpp
srf/triangulate.cpp) srf/triangulate.cpp)
add_executable(solvespace WIN32 add_executable(solvespace WIN32 MACOSX_BUNDLE
${libslvs_HEADERS} ${libslvs_HEADERS}
${libslvs_SOURCES} ${libslvs_SOURCES}
${util_SOURCES} ${util_SOURCES}
${platform_HEADERS} ${platform_HEADERS}
${platform_SOURCES} ${platform_SOURCES}
${platform_BUNDLED_RESOURCES}
${generated_HEADERS} ${generated_HEADERS}
${solvespace_HEADERS} ${solvespace_HEADERS}
${solvespace_SOURCES}) ${solvespace_SOURCES})
@ -252,7 +320,8 @@ if(SPACEWARE_FOUND)
endif() endif()
install(TARGETS solvespace install(TARGETS solvespace
RUNTIME DESTINATION bin) RUNTIME DESTINATION bin
BUNDLE DESTINATION .)
install(FILES unix/solvespace.desktop install(FILES unix/solvespace.desktop
DESTINATION share/applications) DESTINATION share/applications)

View File

@ -0,0 +1 @@
../../unix/solvespace-16x16.png

View File

@ -0,0 +1 @@
../../unix/solvespace-32x32.png

65
src/cocoa/MainMenu.xib Normal file
View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="12F45" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
</dependencies>
<objects>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication"/>
<customObject id="-3" userLabel="Application"/>
<customObject id="-4" userLabel="Application Delegate" customClass="ApplicationDelegate"/>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="SolveSpace" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="SolveSpace" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About SolveSpace" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW">
<connections>
<action selector="preferences:" target="-4" id="xyv-2f-7kO"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide SolveSpace" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit SolveSpace" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-3" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</objects>
</document>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="12F45" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
<capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSViewController">
<connections>
<outlet property="button" destination="nNy-fR-AhK" id="w3z-a4-Khs"/>
<outlet property="view" destination="c22-O7-iKe" id="w2z-a4-Khs"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application"/>
<customView id="c22-O7-iKe">
<rect key="frame" x="0.0" y="0.0" width="294" height="51"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nNy-fR-AhK">
<rect key="frame" x="105" y="12" width="34" height="26"/>
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="f8z-Qp-Igm">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" title="OtherViews" id="VgN-HZ-Q4a"/>
</popUpButtonCell>
<connections>
<binding destination="-2" name="selectedIndex" keyPath="index" id="AXx-uh-tee"/>
</connections>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="z9Z-cA-QIW">
<rect key="frame" x="17" y="17" width="73" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="File Format:" id="2vD-ht-BhF">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="nNy-fR-AhK" firstAttribute="top" secondItem="c22-O7-iKe" secondAttribute="top" constant="15" id="B3P-9V-lvu"/>
<constraint firstItem="nNy-fR-AhK" firstAttribute="leading" secondItem="z9Z-cA-QIW" secondAttribute="trailing" constant="20" id="Uex-s1-7UF"/>
<constraint firstAttribute="bottom" secondItem="nNy-fR-AhK" secondAttribute="bottom" constant="15" id="pPM-eQ-gOD"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="nNy-fR-AhK" secondAttribute="trailing" constant="20" id="rPT-bl-Md7"/>
<constraint firstItem="z9Z-cA-QIW" firstAttribute="baseline" secondItem="nNy-fR-AhK" secondAttribute="baseline" constant="1" id="spD-eU-Frq"/>
<constraint firstItem="nNy-fR-AhK" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="centerX" constant="-40" id="whX-1w-qMB"/>
</constraints>
</customView>
<userDefaultsController representsSharedInstance="YES" id="ybp-e7-hms"/>
</objects>
</document>

1103
src/cocoa/cocoamain.mm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -294,8 +294,12 @@ static void LoadPreferences(void)
Preferences = new Fl_Preferences(dir, "solvespace.org", "solvespace"); Preferences = new Fl_Preferences(dir, "solvespace.org", "solvespace");
} }
void SetWindowTitle(const char *str) { void SetCurrentFilename(const char *filename) {
GraphicsWnd->label(str); if(filename) {
GraphicsWnd->label(std::string("SolveSpace - ") + filename);
} else {
GraphicsWnd->label("SolveSpace - (not yet saved)");
}
} }
void SetMousePointerToHand(bool yes) { void SetMousePointerToHand(bool yes) {
@ -1331,7 +1335,9 @@ int main(int argc, char **argv)
#endif #endif
// Call in to the platform-independent code, and let them do their init // Call in to the platform-independent code, and let them do their init
SS.Init(file); SS.Init();
if(strcmp(file, ""))
SS.OpenFile(file);
// And now it's the main event loop. All calls in to the rest of the // And now it's the main event loop. All calls in to the rest of the
// code will be from the callbacks. // code will be from the callbacks.

View File

@ -39,8 +39,10 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Export 3d &Wireframe...", MNU_EXPORT_WIREFRAME, 0, IN, mFile }, { 1, "Export 3d &Wireframe...", MNU_EXPORT_WIREFRAME, 0, IN, mFile },
{ 1, "Export Triangle &Mesh...", MNU_EXPORT_MESH, 0, IN, mFile }, { 1, "Export Triangle &Mesh...", MNU_EXPORT_MESH, 0, IN, mFile },
{ 1, "Export &Surfaces...", MNU_EXPORT_SURFACES,0, IN, mFile }, { 1, "Export &Surfaces...", MNU_EXPORT_SURFACES,0, IN, mFile },
#ifndef __APPLE__
{ 1, NULL, 0, 0, IN, NULL }, { 1, NULL, 0, 0, IN, NULL },
{ 1, "E&xit", MNU_EXIT, C|'Q', IN, mFile }, { 1, "E&xit", MNU_EXIT, C|'Q', IN, mFile },
#endif
{ 0, "&Edit", 0, 0, IN, NULL }, { 0, "&Edit", 0, 0, IN, NULL },
{ 1, "&Undo", MNU_UNDO, C|'Z', IN, mEdit }, { 1, "&Undo", MNU_UNDO, C|'Z', IN, mEdit },
@ -77,7 +79,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Show Snap &Grid", MNU_SHOW_GRID, '>', IC, mView }, { 1, "Show Snap &Grid", MNU_SHOW_GRID, '>', IC, mView },
{ 1, "Use &Perspective Projection", MNU_PERSPECTIVE_PROJ,'`', IC, mView }, { 1, "Use &Perspective Projection", MNU_PERSPECTIVE_PROJ,'`', IC, mView },
{ 1, NULL, 0, 0, IN, NULL }, { 1, NULL, 0, 0, IN, NULL },
#if defined(HAVE_FLTK) #if defined(HAVE_FLTK) || defined(__APPLE__)
{ 1, "Show Menu &Bar", MNU_SHOW_MENU_BAR, F(12), IC, mView }, { 1, "Show Menu &Bar", MNU_SHOW_MENU_BAR, F(12), IC, mView },
#endif #endif
{ 1, "Show &Toolbar", MNU_SHOW_TOOLBAR, 0, IC, mView }, { 1, "Show &Toolbar", MNU_SHOW_TOOLBAR, 0, IC, mView },
@ -85,7 +87,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, NULL, 0, 0, IN, NULL }, { 1, NULL, 0, 0, IN, NULL },
{ 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, IR, mView }, { 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, IR, mView },
{ 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, IR, mView }, { 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, IR, mView },
#if defined(HAVE_FLTK_FULLSCREEN) || defined(HAVE_GTK) #if defined(HAVE_FLTK_FULLSCREEN) || defined(HAVE_GTK) || defined(__APPLE__)
{ 1, NULL, 0, 0, IN, NULL }, { 1, NULL, 0, 0, IN, NULL },
{ 1, "&Full Screen", MNU_FULL_SCREEN, F(11), IC, mView }, { 1, "&Full Screen", MNU_FULL_SCREEN, F(11), IC, mView },
#endif #endif
@ -157,7 +159,9 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 0, "&Help", 0, 0, IN, NULL }, { 0, "&Help", 0, 0, IN, NULL },
{ 1, "&Website / Manual", MNU_WEBSITE, 0, IN, mHelp }, { 1, "&Website / Manual", MNU_WEBSITE, 0, IN, mHelp },
#ifndef __APPLE__
{ 1, "&About", MNU_ABOUT, 0, IN, mHelp }, { 1, "&About", MNU_ABOUT, 0, IN, mHelp },
#endif
{ -1, 0, 0, 0, IN, 0 } { -1, 0, 0, 0, IN, 0 }
}; };
@ -624,13 +628,13 @@ void GraphicsWindow::EnsureValidActives(void) {
ShowTextWindow(SS.GW.showTextWindow); ShowTextWindow(SS.GW.showTextWindow);
CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow); CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow);
#if defined(HAVE_FLTK) #if defined(HAVE_FLTK) || defined(__APPLE__)
CheckMenuById(MNU_SHOW_MENU_BAR, MenuBarIsVisible()); CheckMenuById(MNU_SHOW_MENU_BAR, MenuBarIsVisible());
#endif #endif
CheckMenuById(MNU_SHOW_TOOLBAR, SS.showToolbar); CheckMenuById(MNU_SHOW_TOOLBAR, SS.showToolbar);
CheckMenuById(MNU_PERSPECTIVE_PROJ, SS.usePerspectiveProj); CheckMenuById(MNU_PERSPECTIVE_PROJ, SS.usePerspectiveProj);
CheckMenuById(MNU_SHOW_GRID, SS.GW.showSnapGrid); CheckMenuById(MNU_SHOW_GRID, SS.GW.showSnapGrid);
#if defined(HAVE_FLTK_FULLSCREEN) || defined(HAVE_GTK) #if defined(HAVE_FLTK_FULLSCREEN) || defined(HAVE_GTK) || defined(__APPLE__)
CheckMenuById(MNU_FULL_SCREEN, FullScreenIsActive()); CheckMenuById(MNU_FULL_SCREEN, FullScreenIsActive());
#endif #endif

View File

@ -716,8 +716,12 @@ void PaintGraphics(void) {
Glib::MainContext::get_default()->iteration(false); Glib::MainContext::get_default()->iteration(false);
} }
void SetWindowTitle(const char *str) { void SetCurrentFilename(const char *filename) {
GW->set_title(str); if(filename) {
GW->set_title(std::string("SolveSpace - ") + filename);
} else {
GW->set_title("SolveSpace - (not yet saved)");
}
} }
void ToggleFullScreen(void) { void ToggleFullScreen(void) {
@ -1490,15 +1494,15 @@ int main(int argc, char** argv) {
TW->show_all(); TW->show_all();
GW->show_all(); GW->show_all();
SS.Init();
if(argc >= 2) { if(argc >= 2) {
if(argc > 2) { if(argc > 2) {
std::cerr << "Only the first file passed on command line will be opened." std::cerr << "Only the first file passed on command line will be opened."
<< std::endl; << std::endl;
} }
SS.Init(argv[1]); SS.OpenFile(argv[1]);
} else {
SS.Init("");
} }
main.run(*GW); main.run(*GW);

View File

@ -9,7 +9,7 @@
SolveSpaceUI SolveSpace::SS; SolveSpaceUI SolveSpace::SS;
Sketch SolveSpace::SK; Sketch SolveSpace::SK;
void SolveSpaceUI::Init(const char *cmdLine) { void SolveSpaceUI::Init() {
SS.tangentArcRadius = 10.0; SS.tangentArcRadius = 10.0;
// Then, load the registry settings. // Then, load the registry settings.
@ -95,18 +95,20 @@ void SolveSpaceUI::Init(const char *cmdLine) {
// configuration file, but we will automatically load those as we need // configuration file, but we will automatically load those as we need
// them. // them.
// Start with either an empty file, or the file specified on the
// command line.
NewFile(); NewFile();
AfterNewFile(); AfterNewFile();
if(strlen(cmdLine) != 0) { }
if(LoadFromFile(cmdLine)) {
strcpy(saveFile, cmdLine); bool SolveSpaceUI::OpenFile(const char *filename) {
bool success = LoadFromFile(filename);
if(success) {
AddToRecentList(filename);
strcpy(saveFile, filename);
} else { } else {
NewFile(); NewFile();
} }
}
AfterNewFile(); AfterNewFile();
return success;
} }
void SolveSpaceUI::Exit(void) { void SolveSpaceUI::Exit(void) {
@ -370,11 +372,9 @@ bool SolveSpaceUI::OkayToStartNewFile(void) {
void SolveSpaceUI::UpdateWindowTitle(void) { void SolveSpaceUI::UpdateWindowTitle(void) {
if(strlen(saveFile) == 0) { if(strlen(saveFile) == 0) {
SetWindowTitle("SolveSpace - (not yet saved)"); SetCurrentFilename(NULL);
} else { } else {
char buf[MAX_PATH+100]; SetCurrentFilename(saveFile);
sprintf(buf, "SolveSpace - %s", saveFile);
SetWindowTitle(buf);
} }
} }

View File

@ -150,6 +150,14 @@ int SaveFileYesNoCancel(void);
# define PAT1(desc,e1) desc "\t*." e1 "\n" # define PAT1(desc,e1) desc "\t*." e1 "\n"
# define PAT2(desc,e1,e2) desc "\t*." e1 "\t*." e2 "\n" # define PAT2(desc,e1,e2) desc "\t*." e1 "\t*." e2 "\n"
# define ENDPAT "All Files\t*" # define ENDPAT "All Files\t*"
#elif defined(__APPLE__)
// Selection pattern format to be parsed by Cocoa glue code:
// "PNG File\tpng\n"
// "JPEG file\tjpg,jpeg\n"
// "All Files\t*"
# define PAT1(desc,e1) desc "\t" e1 "\n"
# define PAT2(desc,e1,e2) desc "\t" e1 "," e2 "\n"
# define ENDPAT "All Files\t*"
#else #else
// Selection pattern format for Win32's OPENFILENAME.lpstrFilter: // Selection pattern format for Win32's OPENFILENAME.lpstrFilter:
// "PNG File (*.png)\0*.png\0" // "PNG File (*.png)\0*.png\0"
@ -238,7 +246,7 @@ void dbp(const char *str, ...);
dbp("tri: (%.3f %.3f %.3f) (%.3f %.3f %.3f) (%.3f %.3f %.3f)", \ dbp("tri: (%.3f %.3f %.3f) (%.3f %.3f %.3f) (%.3f %.3f %.3f)", \
CO((tri).a), CO((tri).b), CO((tri).c)) CO((tri).a), CO((tri).b), CO((tri).c))
void SetWindowTitle(const char *str); void SetCurrentFilename(const char *filename);
void SetMousePointerToHand(bool yes); void SetMousePointerToHand(bool yes);
void DoMessageBox(const char *str, int rows, int cols, bool error); void DoMessageBox(const char *str, int rows, int cols, bool error);
void SetTimerFor(int milliseconds); void SetTimerFor(int milliseconds);
@ -787,7 +795,8 @@ public:
bool tangentArcDeleteOld; bool tangentArcDeleteOld;
// The platform-dependent code calls this before entering the msg loop // The platform-dependent code calls this before entering the msg loop
void Init(const char *cmdLine); void Init(void);
bool OpenFile(const char *filename);
void Exit(void); void Exit(void);
// File load/save routines, including the additional files that get // File load/save routines, including the additional files that get

View File

@ -3,14 +3,20 @@
// //
// Copyright 2015 <whitequark@whitequark.org> // Copyright 2015 <whitequark@whitequark.org>
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#ifdef __APPLE__
#include <OpenGL/GL.h>
#else
#include <GL/glew.h> #include <GL/glew.h>
#endif
#include "gloffscreen.h" #include "gloffscreen.h"
#include "solvespace.h" #include "solvespace.h"
GLOffscreen::GLOffscreen() : _pixels(NULL), _pixels_inv(NULL) { GLOffscreen::GLOffscreen() : _pixels(NULL), _pixels_inv(NULL) {
#ifndef __APPLE__
if(glewInit() != GLEW_OK) if(glewInit() != GLEW_OK)
oops(); oops();
#endif
if(!GL_EXT_framebuffer_object) if(!GL_EXT_framebuffer_object)
oops(); oops();
@ -57,7 +63,9 @@ bool GLOffscreen::begin(int width, int height) {
return false; return false;
} }
uint8_t *GLOffscreen::end() { uint8_t *GLOffscreen::end(bool flip) {
uint32_t *pixels_tgt = flip ? _pixels_inv : _pixels;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
glReadPixels(0, 0, _width, _height, glReadPixels(0, 0, _width, _height,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, _pixels_inv); GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, _pixels_inv);
@ -66,11 +74,13 @@ uint8_t *GLOffscreen::end() {
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, _pixels_inv); GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, _pixels_inv);
#endif #endif
if(flip) {
/* in OpenGL coordinates, bottom is zero Y */ /* in OpenGL coordinates, bottom is zero Y */
for(int i = 0; i < _height; i++) for(int i = 0; i < _height; i++)
memcpy(&_pixels[_width * i], &_pixels_inv[_width * (_height - i - 1)], _width * 4); memcpy(&_pixels[_width * i], &_pixels_inv[_width * (_height - i - 1)], _width * 4);
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return (uint8_t*) _pixels; return (uint8_t*) (flip ? _pixels : _pixels_inv);
} }

View File

@ -21,9 +21,10 @@ public:
bool begin(int width, int height); bool begin(int width, int height);
/* get pixels out of the frame and restore OpenGL state. /* get pixels out of the frame and restore OpenGL state.
the pixel format is ARGB32 with top row at index 0. the pixel format is ARGB32 with top row at index 0 if
flip is true and bottom row at index 0 if flip is false.
the returned array is valid until the next call to begin() */ the returned array is valid until the next call to begin() */
uint8_t *end(); uint8_t *end(bool flip = true);
private: private:
unsigned int _framebuffer; unsigned int _framebuffer;

View File

@ -307,8 +307,13 @@ float SolveSpace::CnfThawFloat(float v, const char *name) {
return u.f; return u.f;
} }
void SetWindowTitle(const char *str) { void SolveSpace::SetCurrentFilename(const char *filename) {
SetWindowText(GraphicsWnd, str); if(filename) {
std::string title = std::string("SolveSpace - ") + filename;
SetWindowText(GraphicsWnd, title.c_str());
} else {
SetWindowText(GraphicsWnd, "SolveSpace - (not yet saved)");
}
} }
void SolveSpace::SetMousePointerToHand(bool yes) { void SolveSpace::SetMousePointerToHand(bool yes) {
@ -1227,7 +1232,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
#endif #endif
// Call in to the platform-independent code, and let them do their init // Call in to the platform-independent code, and let them do their init
SS.Init(file); SS.Init();
if(strcmp(file, ""))
SS.OpenFile(file);
// And now it's the message loop. All calls in to the rest of the code // And now it's the message loop. All calls in to the rest of the code
// will be from the wndprocs. // will be from the wndprocs.