2013-10-28 13:28:42 +08:00
|
|
|
//-----------------------------------------------------------------------------
|
2015-03-17 23:09:59 +08:00
|
|
|
// Utility functions used by the Unix port. Notably, our memory allocation;
|
2013-10-28 13:28:42 +08:00
|
|
|
// we use two separate allocators, one for long-lived stuff and one for
|
|
|
|
// stuff that gets freed after every regeneration of the model, to save us
|
|
|
|
// the trouble of freeing the latter explicitly.
|
|
|
|
//
|
|
|
|
// Copyright 2008-2013 Jonathan Westhues.
|
|
|
|
// Copyright 2013 Daniel Richard G. <skunk@iSKUNK.ORG>
|
|
|
|
//-----------------------------------------------------------------------------
|
2015-03-19 01:02:11 +08:00
|
|
|
#include <time.h>
|
2016-05-19 03:38:17 +08:00
|
|
|
#include <execinfo.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
|
|
|
#ifdef __APPLE__
|
|
|
|
# include <strings.h> // for strcasecmp
|
|
|
|
#endif
|
2013-10-28 13:28:42 +08:00
|
|
|
|
|
|
|
#include "solvespace.h"
|
|
|
|
|
2015-03-24 01:49:04 +08:00
|
|
|
namespace SolveSpace {
|
|
|
|
|
2013-10-28 13:28:42 +08:00
|
|
|
void dbp(const char *str, ...)
|
|
|
|
{
|
|
|
|
va_list f;
|
|
|
|
static char buf[1024*50];
|
|
|
|
va_start(f, str);
|
|
|
|
vsnprintf(buf, sizeof(buf), str, f);
|
|
|
|
va_end(f);
|
|
|
|
|
|
|
|
fputs(buf, stderr);
|
2015-03-18 01:02:04 +08:00
|
|
|
fputc('\n', stderr);
|
2013-10-28 13:28:42 +08:00
|
|
|
}
|
|
|
|
|
2016-05-19 03:38:17 +08:00
|
|
|
void assert_failure(const char *file, unsigned line, const char *function,
|
|
|
|
const char *condition, const char *message) {
|
|
|
|
fprintf(stderr, "File %s, line %u, function %s:\n", file, line, function);
|
|
|
|
fprintf(stderr, "Assertion '%s' failed: ((%s) == false).\n", message, condition);
|
|
|
|
|
2016-07-19 23:40:52 +08:00
|
|
|
#ifndef LIBRARY
|
2016-05-19 03:38:17 +08:00
|
|
|
static void *ptrs[1024] = {};
|
|
|
|
size_t nptrs = backtrace(ptrs, sizeof(ptrs) / sizeof(ptrs[0]));
|
|
|
|
char **syms = backtrace_symbols(ptrs, nptrs);
|
|
|
|
|
|
|
|
fprintf(stderr, "Backtrace:\n");
|
|
|
|
if(syms != NULL) {
|
|
|
|
for(size_t i = 0; i < nptrs; i++) {
|
|
|
|
fprintf(stderr, "%2zu: %s\n", i, syms[i]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for(size_t i = 0; i < nptrs; i++) {
|
|
|
|
fprintf(stderr, "%2zu: %p\n", i, ptrs[i]);
|
|
|
|
}
|
|
|
|
}
|
2016-07-19 23:40:52 +08:00
|
|
|
#endif
|
2016-05-19 03:38:17 +08:00
|
|
|
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
bool PathEqual(const std::string &a, const std::string &b)
|
|
|
|
{
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
// Case-sensitivity is actually per-volume on OS X,
|
|
|
|
// but it is tedious to implement and test for little benefit.
|
|
|
|
return !strcasecmp(a.c_str(), b.c_str());
|
|
|
|
#else
|
|
|
|
return a == b;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-07-26 03:37:48 +08:00
|
|
|
std::string PathSepPlatformToUnix(const std::string &filename)
|
|
|
|
{
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string PathSepUnixToPlatform(const std::string &filename)
|
|
|
|
{
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
2015-12-27 16:09:00 +08:00
|
|
|
FILE *ssfopen(const std::string &filename, const char *mode)
|
|
|
|
{
|
2016-05-19 06:51:36 +08:00
|
|
|
ssassert(filename.length() == strlen(filename.c_str()),
|
|
|
|
"Unexpected null byte in middle of a path");
|
2015-12-27 16:09:00 +08:00
|
|
|
return fopen(filename.c_str(), mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ssremove(const std::string &filename)
|
|
|
|
{
|
2016-05-19 06:51:36 +08:00
|
|
|
ssassert(filename.length() == strlen(filename.c_str()),
|
|
|
|
"Unexpected null byte in middle of a path");
|
2015-12-27 16:09:00 +08:00
|
|
|
remove(filename.c_str());
|
|
|
|
}
|
|
|
|
|
2013-10-28 13:28:42 +08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// A separate heap, on which we allocate expressions. Maybe a bit faster,
|
|
|
|
// since fragmentation is less of a concern, and it also makes it possible
|
|
|
|
// to be sloppy with our memory management, and just free everything at once
|
|
|
|
// at the end.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
typedef struct _AllocTempHeader AllocTempHeader;
|
|
|
|
|
|
|
|
typedef struct _AllocTempHeader {
|
|
|
|
AllocTempHeader *prev;
|
|
|
|
AllocTempHeader *next;
|
|
|
|
} AllocTempHeader;
|
|
|
|
|
|
|
|
static AllocTempHeader *Head = NULL;
|
|
|
|
|
|
|
|
void *AllocTemporary(size_t n)
|
|
|
|
{
|
|
|
|
AllocTempHeader *h =
|
|
|
|
(AllocTempHeader *)malloc(n + sizeof(AllocTempHeader));
|
|
|
|
h->prev = NULL;
|
|
|
|
h->next = Head;
|
2015-09-08 07:41:25 +08:00
|
|
|
if(Head) Head->prev = h;
|
2013-10-28 13:28:42 +08:00
|
|
|
Head = h;
|
2014-04-08 09:51:55 +08:00
|
|
|
memset(&h[1], 0, n);
|
2013-10-28 13:28:42 +08:00
|
|
|
return (void *)&h[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeTemporary(void *p)
|
|
|
|
{
|
|
|
|
AllocTempHeader *h = (AllocTempHeader *)p - 1;
|
|
|
|
if(h->prev) {
|
|
|
|
h->prev->next = h->next;
|
|
|
|
} else {
|
|
|
|
Head = h->next;
|
|
|
|
}
|
|
|
|
if(h->next) h->next->prev = h->prev;
|
|
|
|
free(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeAllTemporary(void)
|
|
|
|
{
|
|
|
|
AllocTempHeader *h = Head;
|
|
|
|
while(h) {
|
|
|
|
AllocTempHeader *f = h;
|
|
|
|
h = h->next;
|
|
|
|
free(f);
|
|
|
|
}
|
|
|
|
Head = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *MemAlloc(size_t n) {
|
|
|
|
void *p = malloc(n);
|
2016-05-19 06:51:36 +08:00
|
|
|
ssassert(p != NULL, "Cannot allocate memory");
|
2013-10-28 13:28:42 +08:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MemFree(void *p) {
|
|
|
|
free(p);
|
|
|
|
}
|
2013-11-18 15:31:23 +08:00
|
|
|
|
|
|
|
void InitHeaps(void) {
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
2015-03-24 01:49:04 +08:00
|
|
|
|
|
|
|
};
|