solvespace/src/platform/w32main.cpp

164 lines
5.5 KiB
C++
Raw Normal View History

//-----------------------------------------------------------------------------
// Our WinMain() functions, and Win32-specific stuff to set up our windows
// and otherwise handle our interface to the operating system. Everything
// outside platform/... should be standard C++ and gl.
//
// Copyright 2008-2013 Jonathan Westhues.
//-----------------------------------------------------------------------------
#include <time.h>
Abstract all (ex-OpenGL) drawing operations into a Canvas interface. This has several desirable consequences: * It is now possible to port SolveSpace to a later version of OpenGL, such as OpenGLES 2, so that it runs on platforms that only have that OpenGL version; * The majority of geometry is now rendered without references to the camera in C++ code, so a renderer can now submit it to the video card once and re-rasterize with a different projection matrix every time the projection is changed, avoiding expensive reuploads; * The DOGD (draw or get distance) interface is now a straightforward Canvas implementation; * There are no more direct references to SS.GW.(projection) in sketch rendering code, which allows rendering to multiple viewports; * There are no more unnecessary framebuffer flips on CPU on Cocoa and GTK; * The platform-dependent GL code is now confined to rendergl1.cpp. * The Microsoft and Apple headers required by it that are prone to identifier conflicts are no longer included globally; * The rendergl1.cpp implementation can now be omitted from compilation to run SolveSpace headless or with a different OpenGL version. Note these implementation details of Canvas: * GetCamera currently always returns a reference to the field `Camera camera;`. This is so that a future renderer that caches geometry in the video memory can define it as asserting, which would provide assurance against code that could accidentally put something projection-dependent in the cache; * Line and triangle rendering is specified through a level of indirection, hStroke and hFill. This is so that a future renderer that batches geometry could cheaply group identical styles. * DrawPixmap and DrawVectorText accept a (o,u,v) and not a matrix. This is so that a future renderer into an output format that uses 2d transforms (e.g. SVG) could easily derive those. Some additional internal changes were required to enable this: * Pixmap is now always passed as std::shared_ptr<{const ,}Pixmap>. This is so that the renderer could cache uploaded textures between API calls, which requires it to capture a (weak) reference. * The PlatformPathEqual function was properly extracted into platform-specific code. This is so that the <windows.h> header could be included only where needed (in platform/w32* as well as rendergl1.cpp). * The SBsp{2,3}::DebugDraw functions were removed. They can be rewritten using the Canvas API if they are ever needed. While no visual changes were originally intended, some minor fixes happened anyway: * The "emphasis" yellow line from top-left corner is now correctly rendered much wider. * The marquee rectangle is now pixel grid aligned. * The hidden entities now do not clobber the depth buffer, removing some minor artifacts. * The workplane "tab" now scales with the font used to render the workplane name. * The workplane name font is now taken from the normals style. * Workplane and constraint line stipple is insignificantly different. This is so that it can reuse the existing stipple codepaths; rendering of workplanes and constraints predates those. Some debug functionality was added: * In graphics window, an fps counter that becomes red when rendering under 60fps is drawn.
2016-05-31 08:55:13 +08:00
#include "config.h"
#include "solvespace.h"
// Include after solvespace.h to avoid identifier clashes.
#include <windows.h>
#include <shellapi.h>
#include <commctrl.h>
#include <commdlg.h>
#ifdef HAVE_SPACEWARE
# include <si.h>
# include <siapp.h>
# undef uint32_t // thanks but no thanks
#endif
using Platform::Narrow;
using Platform::Widen;
#ifdef HAVE_SPACEWARE
// The 6-DOF input device.
SiHdl SpaceNavigator = SI_NO_HANDLE;
#endif
//-----------------------------------------------------------------------------
// Utility routines
//-----------------------------------------------------------------------------
void SolveSpace::OpenWebsite(const char *url) {
ShellExecuteW((HWND)SS.GW.window->NativePtr(),
L"open", Widen(url).c_str(), NULL, NULL, SW_SHOWNORMAL);
}
std::vector<Platform::Path> SolveSpace::GetFontFiles() {
std::vector<Platform::Path> fonts;
std::wstring fontsDirW(MAX_PATH, '\0');
fontsDirW.resize(GetWindowsDirectoryW(&fontsDirW[0], fontsDirW.length()));
fontsDirW += L"\\fonts\\";
Platform::Path fontsDir = Platform::Path::From(Narrow(fontsDirW));
WIN32_FIND_DATA wfd;
HANDLE h = FindFirstFileW((fontsDirW + L"*").c_str(), &wfd);
while(h != INVALID_HANDLE_VALUE) {
fonts.push_back(fontsDir.Join(Narrow(wfd.cFileName)));
if(!FindNextFileW(h, &wfd)) break;
}
return fonts;
}
#ifdef HAVE_SPACEWARE
//-----------------------------------------------------------------------------
// Test if a message comes from the SpaceNavigator device. If yes, dispatch
// it appropriately and return true. Otherwise, do nothing and return false.
//-----------------------------------------------------------------------------
static bool ProcessSpaceNavigatorMsg(MSG *msg) {
if(SpaceNavigator == SI_NO_HANDLE) return false;
SiGetEventData sged;
SiSpwEvent sse;
SiGetEventWinInit(&sged, msg->message, msg->wParam, msg->lParam);
int ret = SiGetEvent(SpaceNavigator, 0, &sged, &sse);
if(ret == SI_NOT_EVENT) return false;
// So the device is a SpaceNavigator event, or a SpaceNavigator error.
if(ret == SI_IS_EVENT) {
if(sse.type == SI_MOTION_EVENT) {
// The Z axis translation and rotation are both
// backwards in the default mapping.
double tx = sse.u.spwData.mData[SI_TX]*1.0,
ty = sse.u.spwData.mData[SI_TY]*1.0,
tz = -sse.u.spwData.mData[SI_TZ]*1.0,
rx = sse.u.spwData.mData[SI_RX]*0.001,
ry = sse.u.spwData.mData[SI_RY]*0.001,
rz = -sse.u.spwData.mData[SI_RZ]*0.001;
SS.GW.SpaceNavigatorMoved(tx, ty, tz, rx, ry, rz,
!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
} else if(sse.type == SI_BUTTON_EVENT) {
int button;
button = SiButtonReleased(&sse);
if(button == SI_APP_FIT_BUTTON) SS.GW.SpaceNavigatorButtonUp();
}
}
return true;
}
#endif // HAVE_SPACEWARE
//-----------------------------------------------------------------------------
// Entry point into the program.
//-----------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, INT nCmdShow)
{
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(icc);
icc.dwICC = ICC_STANDARD_CLASSES|ICC_BAR_CLASSES;
InitCommonControlsEx(&icc);
std::vector<std::string> args = InitPlatform(0, NULL);
#ifdef HAVE_SPACEWARE
// Initialize the SpaceBall, if present. Test if the driver is running
// first, to avoid a long timeout if it's not.
HWND swdc = FindWindowW(L"SpaceWare Driver Class", NULL);
if(swdc != NULL) {
SiOpenData sod;
SiInitialize();
SiOpenWinInit(&sod, (HWND)SS.GW.window->NativePtr());
SpaceNavigator = SiOpen("GraphicsWnd", SI_ANY_DEVICE, SI_NO_MASK, SI_EVENT, &sod);
SiSetUiMode(SpaceNavigator, SI_UI_NO_CONTROLS);
}
#endif
2015-03-29 08:30:52 +08:00
// Use the user default locale, then fall back to English.
if(!SetLocale((uint16_t)GetUserDefaultLCID())) {
SetLocale("en_US");
}
2017-01-05 18:39:08 +08:00
// Call in to the platform-independent code, and let them do their init
2015-03-24 14:45:53 +08:00
SS.Init();
// A filename may have been specified on the command line.
if(args.size() >= 2) {
SS.Load(Platform::Path::From(args[1]).Expand(/*fromCurrentDirectory=*/true));
}
// And now it's the message loop. All calls in to the rest of the code
// will be from the wndprocs.
MSG msg;
DWORD ret;
while((ret = GetMessage(&msg, NULL, 0, 0)) != 0) {
#ifdef HAVE_SPACEWARE
// Is it a message from the six degree of freedom input device?
if(ProcessSpaceNavigatorMsg(&msg)) continue;
#endif
// None of the above; so just a normal message to process.
TranslateMessage(&msg);
DispatchMessage(&msg);
}
#ifdef HAVE_SPACEWARE
if(swdc != NULL) {
if(SpaceNavigator != SI_NO_HANDLE) SiClose(SpaceNavigator);
SiTerminate();
}
#endif
// Free the memory we've used; anything that remains is a leak.
SK.Clear();
SS.Clear();
return 0;
}