After this commit, any transparent triangles are drawn last, which
causes them to not clobber the depth buffer, and so if they overlap
some opaque triangles, then these opaque triangles will be visible.
There are still issues with overlapping transparent triangles,
and with transparent triangles overlapping outlines and entities.
It was broken because of three bugs:
* Uninitialized variables in RunCommand;
* Trying to use (OEM-encoded) main() argc/argv arguments instead
of GetCommandLineW();
* Trying to pass relative paths directly into ssfopen.
Before this commit, if constraints with newly introduced params were
loaded from a file that linked other files, the upgrade code would
attempt to look up a non-existent entity.
All of our executables need resources; e.g. the vector font is
a resource and it is necessary for generation. Before this commit,
the GUI executable loaded the resources in a nice way, and everything
else did it in a very ad-hoc, fragile way.
After this commit, all executables are placed in <build>/bin and
follow the same algorithm:
* On Windows, resources are compiled and linked into every
executable.
* On Linux, resources are copied into <build>/res (which is
tried first) and <prefix>/share/solvespace (which is tried
second).
* On macOS, resources are copied into <build>/res (which is
tried first) and <build>/bin/solvespace.app/Contents/Resources
(which is tried second).
In practice this means that we can add as many executables as we want
without duplicating lots of code. In addition, on macOS, we can
place supplementary executables into the bundle, and they can use
resources from the bundle transparently.
Before this commit, inserting into BSP tree could easily overflow
the stack because we allocate very large stack frames and, on
convex geometries (e.g. a sphere), the BSP tree degenerates into
a "BSP list", thus requiring one large stack frame per triangle.
This can be reproduced by exporting a 2d shaded view of sphere.
After this commit, the stack frames only contan a pointer to
a supplementary data structure, and moreover it only allocates
its fields on demand, conserving heap memory as well.
As a side effect, an arbitrary classifier limit of 50 vertices
is removed.
This commit implements two improvements. First, it rewrites
SMesh::FirstIntersectionWith() to use an optimal (as currently known)
ray tracing algorithm. Second, it rejects triangles without
an associated face entity outright.
This partially reverts commit 3a585ea.
We no longer need this because the VectorsParallel() is gone, and
there is no chance of pivoting wrong when solving.
Before this commit, parallel constraints in 3d are fragile:
constraints that are geometrically fine can end up singular anyway
because VectorsParallel() pivots wrong but converges anyway.
After this commit, much like in cc07058, the constraints are written
in a different form: instead of trying to remove two degrees of
freedom out of three, all three are removed, and one added; namely,
the constraint introduces a free parameter, signed length ratio.
Before this commit, pt-on-line constraints are buggy. To reproduce,
extrude a circle, then add a datum point and constrain it to the
axis of the circle, then move it. The cylinder will collapse.
To quote Jonathan:
> On investigation, I (a) confirm that the problem is
> the unconstrained extrusion depth going to zero, and (b) retract
> my earlier statement blaming extrude and other similar non-entity
> parameter treatment for this problem; you can easily reproduce it
> with a point in 3d constrained to lie on any line whose length
> is free.
>
> PT_ON_LINE is written using VectorsParallel, for no obvious reason.
> Rewriting that constraint to work on two projected distances (using
> any two basis vectors perpendicular to the line) should fix that
> problem, since replacing the "point on line in 3d" constraint with
> two "point on line in 2d" constraints works. That still has
> the hairy ball problem of choosing the basis vectors, which you
> can't do with a continuous function; you'd need Vector::Normal()
> or equivalent.
>
> You could write three equations and make the constraint itself
> introduce one new parameter for t. I don't know how well that
> would work numerically, but it would avoid the hairy ball problem,
> perhaps elegant at the cost of speed.
Indeed, this commit implements the latter solution: it introduces
an additional free parameter. The point being coincident with
the start of the line corresponds to the parameter being zero, and
point being coincident with the end corresponds to one).
In effect, instead of constraining two of three degrees of freedom
(for which the equations do not exist because of the hairy ball
theorem), it constrains three and adds one more.
Before this commit, polylines got flattened but all other entities
got exported with the proper Z coordinate. After this commit, all
entities are exported with proper Z coordinate.
Also, instead of exporting LWPOLYLINE (2d only), POLYLINE (2d/3d)
is exported; as a bonus it is more compatible with 3rd party
software, since it is older.
The only thing we need it anymore is the package version and platform
configuration, so only include it for that. As a result, less files
are rebuilt when the git commit changes and config.h is regenerated.
Before this commit, any visibility toggle would cause a regeneration.
After this commit, toggling visibility of normals and points never
causes a regeneration, and toggling visibility of edges and outlines
only causes a regeneration when they weren't already generated.
FromTransformationOf is called with an identity rotation or
translation for translation and rotation groups, and for every
group that doesn't produce a solid model. This commit omits any
calculations from it when the relevant part of transformation
would change nothing.
This commit results in a ~10% improvement on testcase
woodworking/big-big-big-woodworking-asm, and splitting the condition
into three parts results in a ~5% improvement on testcase
stress/rotate_groups_0.
SSurface::TriangulateInto first populates the mesh with triangles
that have no color, and then paints them, which confused the code
that detects if a mesh is transparent into thinking that all of them
are; and that broke the "draw back faces in red" feature, since it
is disabled for transparent meshes.
The configuration option "draw back faces in red" aids debugging,
in that it allows to visually identify a non-watertight mesh.
When it is disabled, or when the mesh is transparent, we used to not
draw them at all before this commit; after, they are drawn just like
the front faces.
This has two consequences:
1. Inner surfaces of non-watertight meshes are not see-through
anymore. That used to be the behavior in version 2.0, and it
was accidentally broken in 2.1.
2. Transparent meshes look *much* better.
3. Solids made from a union of a non-transparent and a transparent
one look sensibly at all.
This commit also updates the OpenGL 1 renderer to let it render
such meshes correctly.
This commit performs two main changes:
* Alters the shaders to use only strictly conformant GLSL 2.0.
* Alters the Windows UI to use ANGLE via GL ES 2.0 and EGL 1.4.
This commit also drops official support for Windows XP, since ANGLE
requires a non-XP toolset to build. It is still possible to build
SolveSpace for Windows XP using:
cmake -T v120_xp -DOPENGL=1
This commit does three things:
* Recognizes that BeginFrame()/EndFrame() are badly named, since
BeginFrame() sets up framebuffer, and EndFrame() flushes a frame,
and they do not have to be called in pairs; and so renames them
to NewFrame()/FlushFrame().
* Reduces the amount of frame flushes in GraphicsWindow::Paint()
to two, which is the minimum since we use two different cameras
for geometry and UI;
* Changes the FPS measurement code to only take into account
the time spent rendering our main geometry, and not the UI
rendering or window system interaction time.
Before this commit, tooltips in the text window are drawn under
the red "X" indicating a disabled button. After this commit, they
are moved on top of that.
This commit also alters the OpenGL renderers' SetCamera() method
to clear the depth buffer, as that would interfere with drawing
the UI; the toolbar would get occluded by geometry.
To actually achieve improved performance with the OpenGL 2 renderer,
we have to cache geometry that doesn't change when the viewport does
(note that the rendered pixels can change quite dramatically because
we can reconfigure shaders; e.g. stippling can be drawn in screen
coordinates).
This commit adds a BatchCanvas interface that can be implemented
by renderers, and uses it for drawing entities such as lines and
points.
There are two main reasons to desire an OpenGL 2 renderer:
1. Compatibility. The compatibility profile, ironically, does not
offer a lot of compatibility, and our OpenGL 1 renderer will not
run on Android, iOS, or WebGL.
2. Performance. The immediate mode does not scale, and in fact
becomes very slow with only a moderate amount of lines on screen,
and only a somewhat large amount of triangles.
This commit implements a basic OpenGL 2 renderer that uses only
features from the (OpenGL 3.2) core profile. It is not yet faster
than the OpenGL 1 renderer, primarily because it uses a lot of small
draw calls.
This commit uses OpenGL 2 on Linux and Mac OS X directly (i.e. links
to the GL symbols from version 2+); on Windows this is impossible
with the default drivers, so for now OpenGL 1 is still used there.
OpenGL 2 and newer do not have the glPolygonMode(..., GL_LINES) API,
so produce the wireframe on our side. It's somewhat slow, and draws
every line three times, but it is cached when the OpenGL 2 renderer
is used, and this should do for a debugging feature.
This specific implementation seems to have lingered from the days
before IdList was stored sorted. This commit has resulted in a ~5%
improvement in Generate::DIRTY time for modelisation.slvs on a GCC 6
release build.
gcc 6 displays these when compiling in release mode; all of these
warnings except the rankOk one were benign because there would have
been an error about the incomplete switch statement.
The rankOk warning highlighted a real problem: bailing early to
didnt_converge would have branched on an uninitialized variable.
This is a common and convenient behavior; the basename is
pre-selected, so exporting multiple views requires just one keystroke
to put the cursor after the basename.
This is useful in case one wants to create a workplane based on
one of the reference ones, to be explicit, or to avoid fishing out
again the line segments used to create a workplane at an angle.
If a generated mesh is non-watertight, and this is not noticed for
some reason (e.g. the markers are dismissed), and the mesh is
exported for further processing, it could cause problems down
the line.
Before this commit, every debug message was correctly printed
to stdout, but they were all concatenated onto a single line in
the Visual Studio "Output" pane.
GroupsInOrder is an extremely hot function, especially during object
picking: before this commit, it was easy to get second plus latencies
on picking, and after this commit picking is almost real-time.
Abstract the exact details of the OpenGL renderer in the render.h
header; this allows us to use GL-specific types in the renderer
class and functions without including OpenGL (and Windows, where
applicable) headers in every source file.
These points can be used for constraining the width of the text
(or to the width of the text).
The main parts of the commit are:
* TtfFont is restructured to be able to return the aspect ratio
for a given string.
* This aspect ratio is written to the savefile, such that even if
the font is missing, the sketch would still be solved correctly.
* The two additional points are constrained via perpendicularly
to the two main points (which form a v vector).
The compatibility features are as follows:
* When the font is missing in old files, 1:1 aspect ratio is used,
which works for the replacement symbol anyhow.
* When the two additional points are missing in old files, their
would-be positions are calculated and they are moved there,
avoiding 'jumping' of underconstrained sketches.
SolveSpace 2.0 used the height of 'A' (i.e. cap height) to determine
the reference height.
SolveSpace 2.1 completely broke that during transition to Freetype,
and used something more or less random, by using FT_Set_Char_Size
with units_per_EM.
SolveSpace 2.2 attempted to fix that, but also used something more
or less random, by using FT_Request_Size with "unit" values.
Turns out that Freetype actually doesn't have a concept of cap height
at all. It is possible to extract it from the TT_OS2 table that is
present in some TrueType fonts, but it is not present in Microsoft
fonts (the msttcorefonts ones), and for those Linux fonts in which
it is present it doesn't appear very reliable.
So instead, use the height of 'A' instead, like version 2.0 did.
This has the advantage that it is quite bulletproof, and also matches
exactly what the old files are measured against.
One downside is that fonts without an 'A' glyph would not render.
We can deal with that when it becomes a problem.
Apitrace uses swapping buffers to determine frame boundaries; before
this commit, everything solvespace renders gets put into a single
frame. Since we don't use double-buffered rendering, the call does
nothing (and is legal to perform), but apitrace output becomes
readable.
Sometimes, after a large change in a sketch, constraints that are
geometrically fine may still cause the rank test to fail. One way
this can happen is VectorsParallel() pivoting wrong due to the big
move, converging anyways but ending up singular. It would then
re-pivot correctly on the new solution when you re-solve, making
this a transient error. This is visible when dragging the arm in
the jansen-asm.slvs example.
After this commit, if the rank test fails, equations are regenerated
the Jacobian is rewritten, and the rank test is retried, which
prevents these transient errors from interfering with dragging.
The problem described above was invisible before c011444, as rank
test was only performed before solving.
A system solved as REDUNDANT_OKAY is still solved correctly,
even if the UI would consider this an error, in case that
g->allowRedundant==false. So there's no reason to discard this
solution; we might find it useful if a system loses a degree of
freedom while dragging, or to avoid regeneration after redundant
constraints are allowed.
This commit also reverts commit 3ff236c, as that is not necessary
anymore.
Before this commit, the outlines are generated in an arbitrary order
from the kd-tree. This worked just fine for continuous lines, but
for stippling, especially on curves, this meant that most of
the piecewise linear edges would have the stippling phase restart
from zero, leading to a very poor appearance.
These were useful before because chord tolerance depended on the zoom
level; and so the first generation produced a crude mesh used to
set the zoom level, and the second actually did useful work.
Chord tolerance is now independent of the zoom level, so this code
is no longer useful.
Before this commit, a translate group based on another translate
group would always use the "union" boolean operation, which does not
work at all if one wants an array with a difference operation, and
results in degraded performance if one wants an array with
an assemble operation.
This significantly improves performance e.g. in case of a sketch
containing a multitude of wooden panels, as the meshes can be
merely transformed instead of being joined.
The check was actually half-broken from the beginning and
until df83ee4; the thick red line was rendered properly but
the error text was rendered with width 0, which by chance worked
on some GL implementations. That commit has fixed the underlying
bug but left the text line width at 0 to avoid test breakage.
This commit fixes the bug, turns off the check completely, and
updates the tests to account for breakage.
The libspnav library doesn't even define SI_APP_FIT_BUTTON, which
appears to be Windows-specific functionality, perhaps a physical
button remapped with some logic. Just use 0 instead, since that
seems always safe.
OpenGL 1.1 permits implementations to reject non-power-of-2 sized
textures. In practice this only affects the default Windows OpenGL
implementation, i.e. with no vendor drivers installed. This is still
important in case the application runs in a VM.
Unfortunately there is no portable way to open an Unicode path with
std::fstream. On *nix, it is enough to call the const char*
constructor. On MSVC, it is enough to call a nonstandard
const wchar_t* constructor. However, on MinGW, there is no way at all
to construct an std::fstream with a wide path, not even using
undocumented APIs. (There used to be a const wchar_t* overload added
back in libstdc++ 4.7, but it got removed for a reason that I was not
able to find out.)
This fixes a strange problem where GTK 2 (but not GTK 3) with NVidia
drivers would not have a depth buffer, but only during exporting
PNGs, despite the fact that normal rendering path and PNG rendering
path come through the same offscreen rendering code.
This avoids a pitfall where a point and a line are selected that are
not in the current workplane, but since the view is parallel to
the workplane, that's not visible, and incorrect measurement results.
The states are:
* Draw all lines (on top of shaded mesh).
* Draw occluded (by shaded mesh) lines as stippled.
* Do not draw occluded (by shaded mesh) lines.
As usual, the export output follows the screen output.
In 2.0, the distance between the points in the TTF request specified
cap height. In 2.1, that was accidentally changed to some arbitrary
value near cap height instead, due to a 72pt factor mess-up.
This commit restores the old behavior.
We're using gcov+lcov, since these tools appear to be the only
usable ones that use the SC/CC metric; and measuring just the line
coverage would be practically criminal negligence.
gcov only works with GCC and Clang, and MSVC's own coverage
measurement tools are not up to the task; so MSVC is out of luck.
This commit alters the build system substantially; it adds another
platform, `headless`, that provides stubs in place of all GUI
functions, and provides a library `solvespace_headless` alongside
the main executable. To cut down build times, only the few files
that have #if defined(HEADLESS) are built twice for the executable
and the library; the rest is grouped into a new `solvespace_cad`
library. It is not usable on its own and just serves for grouping.
This commit also gates the tests behind a -DENABLE_TESTS=ON CMake
option, ON by default (but suggested as OFF in the README so that
people don't ever have to install cairo to build the executable.)
The tests introduced in this commit are (so far) rudimentary,
although functional, and they serve as a stepping point towards
introducing coverage analysis.
Without -fno-exceptions, the branch coverage information is
practically useless, as every call becomes a branch.
The functionality of Expr is retained as-is, although SjLj error
handling is a maintenance nightmare. However, the entire parser
probably should be eventually replaced, so for now it is not
a great concern.
SurfaceRenderer is a new renderer implementing the Canvas interface
running entirely on the CPU; it projects strokes and triangles
in the exact same way as OpenGL would, and it can be used for
rendering into raster or vector 2d surfaces.
The only user of that was the background image, and it was flipped
again when it was rendered, so the two bugs masked out each other.
This adds a `bool flip` to ReadPng and FromPng, since that's cheap
to do when writing the PNG file, expensive on the pixel arrays,
and sometimes inconvenient in OpenGL due to offsets.