This commit integrates the bitmap font in the resource system, so
that cross-compilation would be easier.
The font handling code was carefully written to do glyph parsing
lazily; in practice this means that after this commit, startup
is less than 25ms slower, most of it spent in inflate().
This should also result in faster rendering, since there is no
rampant plane switching anymore; instead, all characters that are
actually used are stashed into same one texture.
This commit integrates icons in the resource system so that they
can be loaded (or reloaded, without restarting) in @2x mode, which
will be added in a future commit. png2c is no longer necessary.
png2c used to perform the following transformation:
if(r + g + b < 11) r = g = b = 11;
This is now achieved by switching the icons to RGBA mode and adding
alpha channel with the following imagemagick invocation, which is
equivalent to the transformation above:
for i in *.png; do
convert -fuzz 4% -channel rgba -matte \
-fill "rgba(255,255,255,0)" -opaque black \
$i $i
done
The Debian package solvespace now includes /usr/share/solvespace;
this should be split out into solvespace-data later.
Without resources, it makes no sense anymore to keep these in
separate subdirectories: unixutil* is shared between Cocoa
and GTK ports, and gloffscreen* should be shared between all ports
(but it's still platform-specific).
Currently, icons, fonts, etc are converted to C structures at compile
time and are hardcoded to the binary. This presents several problems:
* Cross-compilation is complicated. Right now, it is necessary
to be able to run executables for the target platform; this
happens to work with wine-binfmt installed, but is rather ugly.
* Icons can only have one resolution. On OS X, modern software is
expected to take advantage of high-DPI ("Retina") screens and
use so-called @2x assets when ran in high-DPI mode.
* Localization is complicated. Win32 and OS X provide built-in
support for loading the resource appropriate for the user's
locale.
* Embedding strings can only be done as raw strings, using C++'s
R"(...)" literals. This precludes embedding sizable strings,
e.g. JavaScript libraries as used in Three.js export, and makes
git history less useful. Not embedding the libraries means we
have to rely on external CDNs, which requires an Internet
connection and adds a glaring point of failure.
* Linux distribution guidelines are violated. All architecture-
independent data, especially large data such as fonts, is
expected to be in /usr/share, not in the binary.
* Customization is impossible without recompilation. Minor
modifications like adding a few missing vector font characters
or adjusting localization require a complete development
environment, which is unreasonable to expect from users of
a mechanical CAD.
As such, this commit adds a resource system that bundles (and
sometimes builds) resources with the executable. Where they go is
platform-dependent:
* on Win32: into resources of the executable, which allows us to
keep distributing one file;
* on OS X: into the app bundle;
* on other *nix: into /usr/share/solvespace/ or ../res/ (relative
to the executable path), the latter allowing us to run freshly
built executables without installation.
It also subsides the platform-specific resources that are in src/.
The resource system is not yet used for anything; this will be added
in later commits.
A previous attempt to fix this was done in 0128b8679. However, it was
not rigorous. The added offset was dependent on font size and it
introduced an error into edit control positioning. Further, it is
irrelevant to non-workplanes.
After this commit, the workplane drawing code adds a fixed offset
instead. Also, the "tab" is enlarged to not overlap with #XY etc.
Without this, if we have e.g.:
* a/x.slvs
* a/y.slvs importing a/x.slvs
and copy a/ to b/, then loading b/y.slvs would load a/x.slvs, which
is rather surprising.
Before this commit, e.g. a 120° angle could be exported as its
supplementary 60° angle but it would still say 120° in the label.
After this commit, the right angle is selected in DXF-based software.
Similarly, it roundtrips through SolveSpace correctly.
This hint is not recommended for direct use by applications, and for
a good reason: it's very annoying. Moreover, what we want is not
"keep above" but rather "keep on the same layer as graphics window",
which is already achieved by setting window type to "utility"
on GNOME and Unity WMs, and by setting the transient window hint
for the text window on KDE WM.
This screws up window managers like fvwm, which don't respect
the ICCCM "Keep Above" flag. I don't remember why it's there and
it doesn't appear that removing it has any ill effect.
This is good practice and helps to catch bugs. Several changes
were made to accomodate the newly enabled warnings:
* -Wunused-function:
* in exposed/, static functions that were supposed to be inlined
were explicitly marked as inline;
* some actually unused functions were removed;
* -Wsign-compare: explicit conversions were added, and in
the future we should find a nicer way than aux* fields;
* -Wmissing-field-initializers: added initializers;
* -Wreorder: reordered properly;
* -Wunused-but-set-variable: remove variable.
-Wunused-parameter was turned off as enabling it would result in
massive amount of churn in UI code. Despite that, we should enable
it at some point as it has a fairly high SNR otherwise.
This is done because a meaningful union extrusion is almost never
a meaningful difference extrusion, and saves a bunch of common
manual work.
To avoid creating invalid sketches this isn't done when there are any
constraints.
Specifically:
* touchscreen devices are now supported;
* rotation is now more like what SolveSpace itself does.
The code is split in two parts because MSVC can't handle string
literals longer than 16Ki.
Before this commit, when exporting a vector file without the shaded
model shown, or similarly when using formats that we do not export
the mesh to, we still generate (and then discard) the mesh in paint
order. This is a waste of time.
The immediate reason for refactoring this was that the GTK port broke
after 52af7256 since config.h is not included anymore, but it was
a fragile piece of code I will shed no tears for.
While we're at it, get rid of the mutable std::string &file to be
consistent with our conventions.
config.h now includes the git hash and so, as long as it's included
in solvespace.h, any change of git HEAD will trigger a complete
recompilation, which makes bisecting especially annoying.
While we're at it, remove HAVE_STDINT_H from it, since we require
C++11 and all MSVC versions that include C++11 also include stdint.h.
Specifically:
* Group Info
* Style Info
* Assign to Style → Newly Created Custom Style...
These context actions are meaningless without viewing or manipulating
text window.
Before this commit, the initial state allCoplanar=false took
precedence over allNonZeroLen=false, since detecting a zero-length
edge short-circuits AssembleLoops.
Grid fitting is performed only on glyph boundaries, since glyphs
include curves converted to pwl, which would be mangled by per-point
grid fitting.
Grid fitting is only performed when the plane in which text is
laid out is parallel to the viewing plane.
Grid fitting is only performed when rendering for display; there
are no devices with dpi low enough for grid fitting to become
profitable, and in any case we cannot predict what the dpi would
be anyway.
First, a larger origin offset is applied in ssglWriteText. This moves
the text so that it doesn't overlap the workplane boundary.
Second, a different offset is applied in ssglWriteTextRefCenter.
After this, the middle stroke of "E" is vertically aligned with
the reference point, and the overall label is horizontally aligned
with the reference point more precisely.
Before this commit, the graphics window edit control always had
a width of 30 average character widths.
After this commit, the edit control has a width of 5 average
character widths (for numeric constraints) or 30 average character
widths (for comment constraints), or just enough to display
the entire value being edited, whichever is greater.
This makes the edit control overlap the sketch less in case of
editing numeric constraints (since in most cases, the numbers being
edited are short), and removes annoying scrolling in case of editing
long comments.
Before this commit, the position of the edit box was adjusted
by trial and error, as far as I can tell. This commit changes
the positioning machinery for edit controls as follows:
The coordinates passed to ShowTextEditControl/ShowGraphicsEditControl
now denote: X the left bound, and Y the baseline.
The font height passed to ShowGraphicsEditControl denotes
the absolute font height in pixels, i.e. ascent plus descent.
Platform-dependent code uses these coordinates, the font metrics
for the font appropriate for the platform, and the knowledge of
the decorations drawn around the text by the native edit control
to position the edit control in a way that overlays the text inside
the edit control with the rendered text.
On OS X, GNU Unifont (of height 16) has metrics identical to
Monaco (of height 15) and so as an exception, the edit control
is nudged slightly for a pixel-perfect fit.
Also, since the built-in vector font is proportional, this commit
also switches the edit control font to proportional when editing
constraints.
Before this commit, solids in the viewport were rendered with
"emphasized edges", with the intention to highlight selectable faces.
However, selectable faces are already surrounded by entities, and
so rendering emphasized edges adds little value.
After this commit, solids in the viewport are always rendered with
"sharp edges", like they are exported.
A new button is added, "Show/hide outline of solid model".
When the outline is hidden, it is rendered using the "solid edge"
style. When the outline is shown, it is rendered using the "outline"
style.
In SolveSpace's true WYSIWYG tradition, the 2d view export follows
the rendered view exactly.
Moreover, shell edges are not rendered anymore, since there is not
much need in them anymore and not drawing them lessens the overlap
between various kinds of lines, which already includes entities,
solid edges and outlines.
Before this change, the two buttons "Show/hide shaded model" (S) and
"Show/hide hidden lines" (H) resulted in drawing the following
elements in the following styles:
Button | Non-occluded | Non-occluded | Occluded | Occluded
state | solid edges | entities | solid edges | entities
--------+--------------+--------------+-------------+--------------
!S !H | | | solid-edge | entity style
--------+ | +-------------+--------------
S !H | | | invisible
--------+ solid-edge | entity style +-------------+--------------
!S H | | | |
--------+ | | solid-edge | entity style
S H | | | |
--------+--------------+--------------+-------------+--------------
After this change, they are drawn as follows:
Button | Non-occluded | Non-occluded | Occluded | Occluded
state | solid edges | entities | solid edges | entities
--------+--------------+--------------+-------------+--------------
!S !H | | | solid-edge | entity style
--------+ | +-------------+--------------
S !H | | | invisible
--------+ solid-edge | entity style +-------------+--------------
!S H | | | |
--------+ | | hidden-edge | stippled¹
S H | | | |
--------+--------------+--------------+-------------+--------------
¹ entity style, but the stipple parameters taken from hidden-edge
In SolveSpace's true WYSIWYG tradition, the 2d view export follows
the rendered view exactly.
Also, it is now possible to edit the stipple parameters of built-in
styles, so that by changing the hidden-edge style to non-stippled
it is possible to regain the old behavior.
Before this commit, "emphasized edges" were displayed as well as
exported. An "emphasized edge" is an edge between triangles that
come from different faces. They are helpful in the rendered
display because they hint at the locations of faces, but not
in the 2d export since they just clutter the drawing.
After this commit, "emphasized edges" are displayed but "sharp
edges" are exported. A "sharp edge" is an edge between triangles
where the two matching vertexes have different normals, indicating
a discontiguity in the surface. "Sharp edges" are also displayed
while post-viewing the exported geometry.
According to the C++ standard, "this" is never NULL, so checks
of the form "if(!this)" can be legally optimized out. This
breaks SolveSpace on GCC 6, and probably on other compilers and
configurations.
Fix iconutil build errors: “Iconset contains no image resources.”,
followed by “Failed to generate ICNS.”
The error is produced by iconutil because the AppIcon.iconset contains
only symbolic links to the icon resources which aren’t followed.
Replace the symbolic links with duplicates of the original resources,
as well as conform to the “High Resolution Guidelines for OS X” by
adding additional sizes and dpi.
This change is quite subtle. The goal is to improve responsiveness
of highlighting even further. To understand this change you need
to keep in mind that Windows and Gtk have dramatically different
behavior for paint (WM_PAINT in Windows, expose in Gtk) and
mouse move events.
In Windows, WM_PAINT and WM_MOUSEMOVE, unless sent explicitly,
are synthesized: WM_MOUSEMOVE is delivered when there are no other
messages and the current cursor position doesn't match the remembered
one, and WM_PAINT is delivered when there are no other messages,
even WM_MOUSEMOVE. This is pretty clever because it doesn't swamp
programs that are slow to process either of those events with even
more of them, ensuring they remain responsive.
In Gtk, expose events are delivered at the end of the frame whenever
there is an invalid view, and every single mouse move that happened
will result in a separate event.
If mouse move events are handled quickly, then the behavior is
identical in either case:
* process mouse move event
* perform hit testing
* invalidate view
* no more events to process!
* there are invalid views
* repaint
If, however, mouse move events are handled slower, then the behavior
diverges. With Gtk:
* process mouse move event
* perform hit testing (slow)
* while this happens, ten more mouse move events are added
* invalidate view
* end of frame!
* there are invalid views
* repaint
* process mouse move event...
As a result, the Gtk-hosted UI hopelessly lags behind user input.
This is very irritating.
With Windows:
* process mouse move event
* perform hit testing (slow)
* while this happens, mouse was moved
* invalidate view
* process mouse move event...
As a result, the Windows-hosted UI never repaints while the mouse
is moved. This is also very irritating.
Commit HEAD^ has fixed the problems with Gtk-based UI by making
hit testing so fast that mouse move events never quite overflow
the queue. There's still a barely noticeable lag but it's better.
However, the problems with Windows remained because while the queue
doesn't *overflow* with the faster hit testing code, it doesn't go
*empty* either! Thus we still don't repaint.
This commit builds on top of HEAD^ and makes it so that we don't
actually hit test anything if we haven't painted the result of
the previous hit test already. This fixes the problem on Windows
but also helps Gtk a little bit.
Curiously, the Cocoa-based UI never suffered from any of these
problems. To my understanding (it's somewhat underdocumented), it
processes mouse moves like Windows, but paints like Gtk.
This results in massive performance improvements for hit testing.
Files with very large amounts of entities (e.g. [1]) inflict
a delay of several seconds between moving the pointer and
highlighting an entity in commit HEAD^^^, whereas in this commit
the delay is barely perceptible.
[1]: http://solvespace.com/forum.pl?action=viewthread&parent=872
Before this commit, trying to export image on *nix platforms yielded
a black rectangle, since since there is nowhere to render to
when we're not in a GUI toolkit draw callback.
On Windows, nothing changes: we do a repaint without the toolbar,
glReadPixels, export. On *nix, we create another offscreen rendering
context, render into it, then destroy it. As a bonus this avoids
some minor flickering that would happen if we reused the regular
rendering path.
We had to fork libdxfrw since the upstream doesn't have a git
repository, a CMake buildsystem, and is quite buggy.
libdxfrw is also used in LibreCAD, but they just vendored
their version.
Before this commit, if a pt-line-distance constraint is placed so
that the dimension line doesn't touch the line, no extension is
drawn. After this commit, an extension line will be drawn towards
the nearest end of the line.
This is an artificial restriction that serves no useful purpose.
Just switch to the previous group if asked to delete the current
one.
The ClearSuper() calls are reshuffled, since TW.ClearSuper() calls
TW.Show() and so has to be called while the sketch is still valid,
whereas GW.ClearSuper() also recreates the default group and thus
it should be called after the first RemoveById+GenerateAll pair,
or it'll recreate the default group before the entities on it have
a chance to be pruned.
Switching active group by itself is not an editing but a viewing
action; the active group is not recorded in the savefile. However,
the entity visibility status is, and this is annoying when source
control is used, because e.g. looking up dimensions in one of
the inner groups whose display was turned off ends up changing
the savefile.
When the display has to be turned on manually, this modification
of the file becomes explicit, so there's no longer any question
of what action modified the file.
This can also be convenient when inserting a group in the middle
of the stack, which will be implemented in the future.
Most of these were just converting char* into std::string back and
forth; some more used ReadUTF8, which was converted to use nicer
STL-style iterators over UTF-8 text.
The remaining ones are:
* arguments to Expr::From, which we'll change when refactoring
the expression lexer;
* arguments to varargs functions, which we'll change when adding
localization (that requires custom printf-style functions to
allow for changing argument order);
* arguments where only string literals are ever passed, which
are OK;
* in platform-specific code, which is OK.
CMake can properly quote inputs to custom commands itself; this is
governed by the VERBATIM flag. If we pass this flag, no quoting
needs to be done except for compiler/linker flags and diagnostic
messages, as CMake doesn't treat whitespace expanded from variables
the same way it treats whitespace that separates arguments.
Scoped "Zoom to Fit" is convenient for working on large models.
I (whitequark) have considered a separate shortcut, but its
usefulness is unclear and in any case it can be easily added
if desired.
In my (whitequark's) experience this warning tends to expose
copy-paste errors with a high SNR, so making a few fragments
slightly less symmetric is worth it.
Also mollify -Wlogical-op-parentheses while we're at it.
After commit 2f734d9, inactive groups are no longer regenerated
for trivial changes, e.g. changing parameters, so it's possible to
switch to an earlier group and work on it without incurring
the computational (slowdown) and cognitive (annoyance by red
background) overhead of later groups failing to solve.
However, if a group--any group anywhere--was not solved OK,
the interface reacted accordingly, which diminished usefulness of
the change, especially given that, if we have groups A and B with
B depending on A, if B is broken by a change in A and we activate A
and fix it, B will not be regenerated.
After this commit, only active groups are considered when deciding
if generating the entire sketch would fail.
This font is less complete than our bitmap font, Unifont: Unifont
has essentially complete Unicode coverage and LibreCAD's font only
has Latin, Cyrillic and Japanese, but it can be extended rather
easily, so this should be fine for now.
These embedded fonts fatten glhelper.o quite a bit:
bitmapfont.table.h is about 8M in gzip-compressed bitmaps and
vectorfont.table.h is about 2M in raw vector data.
In spite of that it takes just around five seconds to build
glhelper.c on my laptop, so it should be fine.
The final executable grows from about 2M to about 8M, but this
is a small price to pay for fairly extensive i18n support.
The new font has somewhat different metrics, so the rendering
code has been fudged to make it look good.
Benefits:
* Much simpler code.
* Handles the entire TTF spec, not just a small subset that
only really worked well on Windows fonts.
* Handles all character sets as well as accented characters.
* Much faster parsing, since Freetype lazily loads and
caches glyphs.
* Support for basically every kind of font that was invented,
not just TTF.
Note that OpenType features, e.g. ligatures, are not yet supported.
This means that Arabic and Devanagari scripts, among others, will
not be rendered in their proper form.
RTL scripts are not supported either, neither in TTF nor in
the text window. Adding RTL support is comparatively easy, but
given that Arabic would not be legibly rendered anyway, this is not
done so far.
We are going to use freetype instead of the old custom TTF parser,
since the old parser has many annoying bugs when handling non-Latin
fonts and fixing it is not really worth the time.
On Windows, Freetype is built from a submodule.
On Linux and OS X, Freetype is provided together with the desktop,
though development files have to be installed separately.
Commit 89eb208 has improved the overall situation with chord
tolerance, but it changed the display chord tolerance to use
an absolute value in millimeters as a stopgap measure.
This commit changes the display chord tolerance to be specified
in percents of entity bounding box instead of millimeters.
As a result, the linearized curves are both zoom level and sketch
scale independent.
In order to compute the bounding box, all entities are generated
twice. However, this shouldn't result in a noticeable slowdown,
since the bounding box calculation does not need the expensive
triangle mesh generation and the solver will converge immediately
on the second run.
Since the meaning of the preference has changed, a new name is
used (ChordTolerancePct instead of ChordTolerance), so that it
would be reset to the default value after updating SolveSpace.
The default value, 0.5%, was selected using trial and error by
judging whether cylinders of moderate dimensions were looking
aesthetically pleasing enough.
After this change, the only real function of the spacebar
shortcut is to reload imported groups, since manual regeneration
should not change anything anymore unless there is a bug.
Before this commit, a single chord tolerance was used for both
displaying and exporting geometry. Moreover, this chord tolerance
was specified in screen pixels, and as such depended on zoom level.
This was inconvenient: exporting geometry with a required level of
precision required awkward manipulations of viewport. Moreover,
since some operations, e.g. mesh watertightness checking, were done
on triangle meshes which are generated differently depending on
the zoom level, these operations could report wildly different
and quite confusing results depending on zoom level.
The chord tolerance for display and export pursue completely distinct
goals: display chord tolerance should be set high enough to achieve
both fast regeneration and legible rendering, whereas export chord
tolerance should be set to match the dimension tolerance of
the fabrication process.
This commit introduces two distinct chord tolerances: a display
and an export one. Both chord tolerances are absolute and expressed
in millimeters; this is inappropriate for display purposes but
will be fixed in the next commits.
After exporting, the geometry is redrawn with the chord tolerance
configured for the export and an overlay message is displayed;
pressing Esc clears the message and returns the display back to
normal.
Instead of always using two points on every curve, with a hack for
some cubics edge case, use three points on the first iteration and
one point on every further iteration. This both faster and more
correct.
Before this change, groups and their meshes were generated even past
the active group, which, in cause the mesh was broken, caused red
marks to appear for no apparent reason. Furthermore, it unnecessarily
slows down regeneration.
Instead, grab it from hoveredRow, since almost always (with only one
exception) this is where the edit control has to be shown.
This makes it much easier to adjust views, e.g. add a new editable
field in the middle of configuration view, because it's not necessary
to manually change and test all the indexes below the row being
changed.
Additionally, it removes a lot of awkward and opaque row calculations.
The commit 11f29b123 has replaced most of the uses of sprintf,
but there were still many remaining in Screen* functions, and it
was annoyingly inconsistent. Moreover, while most usage of sprintf
there was fine, it is bad hygiene to leave stack overflow prone
code around.
It's not possible to put non-POD elements in a union, and a struct
with accessors is a more elegant solution than a union with POD
elements and explicit casts for the rest.
This setting is generally useful, but it especially shines when
assembling, since the "same orientation" and "parallel" constraints
remove three and two rotational degrees of freedom, which makes them
impossible to use with 3d "point on line" constraint that removes
two spatial and two rotational degrees of freedom.
The setting is not enabled for all imported groups by default
because it exhibits some edge case failures. For example:
* draw two line segments sharing a point,
* constrain lengths of line segments,
* constrain line segments perpendicular,
* constrain line segments to a 90° angle.
This is a truly degenerate case and so it is not considered very
important. However, we can fix this later by using Eigen::SparseQR.
Before this commit, overconstraining a system past a certain point
resulted in a wrong error message: instead of "redundant constraints",
"unsolvable constraints" was displayed.
To reproduce, place more six or more length constraints with the same
value onto the same line segment.
When a solver error arises after a change to the sketch, it should
be easy to understand exactly why it happened. Before this change,
two functionally distinct modes of failure were lumped into one:
the same "redundant constraints" message was displayed when all
degrees of freedom were exhausted and the had a solution, but also
when it had not.
To understand why this is problematic, let's examine several ways
in which we can end up with linearly dependent equations in our
system:
0) create a triangle, then constrain two different pairs of edges
to be perpendicular
1) add two distinct distance constraints on the same segment
2) add two identical distance constraints on the same segment
3) create a triangle, then constrain edges to lengths a, b, and c
so that a+b=c
The case (0) is our baseline case: the constraints in it make
the system unsolvable yet they do not remove more degrees of freedom
than the amount we started with. So the displayed error is
"unsolvable constraints".
The constraints in case (1) remove one too many degrees of freedom,
but otherwise are quite like the case (0): the cause of failure that
is useful to the user is that the constraints are mutually
incompatible.
The constraints in cases (2) and (3) however are not like the others:
there is a set of parameters that satisfies all of the constraints,
but the constraints still remove one degree of freedom too many.
It makes sense to display a different error message for cases (2)
and (3) because in practice, cases like this are likely to arise from
adjustment of constraint values on sketches corresponding to systems
that have a small amount of degenerate solutions, and this is very
different from systems arising in cases like (0) where no adjustment
of constraint values will ever result in a successful solution.
So the error message displayed is "redundant constraints".
At last, this commit makes cases (0) and (1) display a message
with only a minor difference in wording. This is deliberate.
The reason is that the facts "the system is unsolvable" and
"the system is unsolvable and also has linearly dependent equations"
present no meaningful, actionable difference to the user, and placing
emphasis on it would only cause confusion.
However, they are still distinguished, because in case (0) we
list all relevant constraints (and thus we say they are "mutually
incompatible") but in case (1) we only list the ones that constrain
the sketch further than some valid solution (and we say they are
"unsatisfied").
Before this change, it was possible to adjust constraints in a way
that removes a degree of freedom and makes the sketch unsolvable,
but rank test was performed before solving the system, and an error
was not displayed immediately. Instead, a solution would seemingly
be found, but it would be very unstable--unrelated changes to
the sketch would cause rank test to fail.
To reproduce the bug, do this:
* Draw a triangle.
* Create a length constraint for all sides.
* Set side lengths to a, b, and c such that a + b = c.
* Add a line segment.
The current messages accurately reflect what happens to the system
of equations that represents the sketch, but can be quite confusing
to users that only think in terms of the constraints.
We use "unsolvable" and not "impossible" because while most of
the cases that result in this error message will indeed stem from
mutually exclusive sets of constraints, it is still possible that
there is some solution that our solver is unable to find using
numeric methods.
After commit 11f29b12, we no longer have a convenient way to indicate
that the edit control should be moved without changing its contents;
the old code trying to do this caused a crash, since constructing
an std::string from a NULL char* is invalid.
This went undetected during testing, since on Linux, recent
GTK versions will munge scroll events while the edit box has
a modal grab.
I could've fixed the feature, but opted to remove it, since being able
to scroll the edit box out of visible region is more likely to result
in confusion than ever be useful.
Most people just want a single self-contained .html file, but more
advanced usage will involve embedding in a webpage, where the default
viewer would be copied and customized, and fed with bare mesh export.
Make the union anonymous so that its elements can be addressed
directly. Then, move the Expr *b field into the union, as it
already is never used at the same time as any of the union members.
It works. Mostly. Sort of. Only on Windows fonts. Sometimes it
randomly refuses to render glyphs (try `х`, that's not a latin ex).
I'm not really sure why, the logic seems right.
Why do we have a homegrown TTF parser anyway? It's kind of awful.
It breaks on any slightly unusual input. It plows through UTF-16BE
font names like a nuclear-powered steamroller. It outright ignores
composite glyphs (is that why it's broken this time?). The kerning
is seizure-inducing. It ignores any characters outside BMP by design.
Maybe we should just replace it with freetype.
This removes the arbitrary 64 byte restriction (which effectively
limits us to as little as 16 Unicode characters with CJK encodings),
makes classes smaller, and is easier to use.
As a consequence of making the length of all ex-NameStr fields
unbounded, all functions that returned a buffer derived from those
were changed to return std::string. Then, functions that are
contextually similar to the ones described above were changed
to return std::string. Then, functions that now happened to mostly
take an std::string argument converted to a C string were changed
to accept std::string.
This has produced a bit of churn, but is probably for the better.
Now it is possible to give non-ASCII names to groups
as well as see non-ASCII filenames of imported files.
In the future this makes localization possible.
This works for LTR languages, such as European and CJK,
but not RTL such as Arabic. Does Arabic even exist in
monospaced form? I have no idea.
After this commit, SolveSpace can robustly handle non-ASCII filenames
on every OS. Additionally, on Windows, filenames longer than 260
characeters can be used, and files on network shares can be opened
directly, without mounting them as a network drive.
After this commit, SolveSpace always uses UTF-8 strings internally
(represented as char* and std::string) on every OS, for everything:
UI labels, paths and user input. OS X always uses UTF-8; on Windows,
strings are converted at boundary; and on Linux/BSD/etc SolveSpace
refuses to start unless the current locale is UTF-8. This will
negatively affect literally no one.
This commit does not bring forth any user-visible improvement yet;
in order to correctly handle Unicode in filenames, it is still
necessary to change the fopen calls to _wfopen on Windows.
After this commit, SolveSpace deals with paths as follows:
* Paths are generally treated as opaque platform-specific strings.
This helps on Linux, because paths on Linux don't have any
specific encoding and it helps to avoid any operations on them.
* The UI in some places wants to get a basename. In this case,
the newly introduced PATH_SEP is used. This allows to treat
backslash as a regular character, which it is on Linux and OS X.
* The only place where any nontrivial operations on paths are
performed is the g->impFile/impFileRel logic.
Specifically, when saved, g->impFile always contains an absolute
path with separators of the current platform, and g->impFileRel
always contains a relative path with UNIX separators. This allows
to treat backslash as a regular character.
Old files will contain g->impFileRel with Windows separators;
these are detected by looking for a drive letter in g->impFile
and in that case mapping Windows separators to UNIX ones.
There is no need to treat UNIX separators (forward slashes) in
any special way on Windows because there is no way on Windows,
not even via UNC paths, to create or address a directory entry
with a forward slash in its name.
What do we gain from this? Several things.
* First, usage of PATH_MAX (the POSIX constant) is eliminated.
PATH_MAX is actually a lie; Linux and OS X (and probably other BSDs
too) do not have an actual path length limit. Linux claims 4096,
OS X claims 1024, but it is trivial to construct paths that are
longer.
* Second, while Windows does enforce a limit of MAX_PATH (the Win32
constant) for its ASCII functions, the Unicode variants, when
used with UNC paths, do not have this restriction.
The capability to use UNC paths is useful by itself, as it allows
to access files on network shares directly.
* Third, representing paths as std::string will make it easier to
interoperate with *W WinAPI functions later.
On Windows, freeze.{cpp,h} was factored into w32main.cpp.
The old implementation was too redundant and leaked registry
key handles.
On all platforms, Cnf* functions now use std::string.
This simplifies code everywhere, but will be particularly useful
when the Windows port switches to the *W WinAPI functions.
This is necessary to store non-POD classes in these containers.
Note that List and IdList do not use MemRealloc anymore;
this is necessarily (slightly) less efficient, but is the right
semantics, as you cannot just move non-POD types, e.g. std::string,
around in memory. All STL containers provide the same guarantees
and share the performance hit.
The slowdown is mostly mitigated by moving the contained objects,
so that no additional heap allocations or copies occur beyond
that of the object itself.
This will allow us to use non-POD classes inside these objects
in future and is otherwise functionally equivalent, as well
as more concise.
Note that there are some subtleties with handling of
brace-initialization. Specifically:
On aggregates (e.g. simple C-style structures) using an empty
brace-initializer zero-initializes the aggregate, i.e. it makes
all members zero.
On non-aggregates an empty brace-initializer calls the default
constructor. And if the constructor doesn't explicitly initialize
the members (which the auto-generated constructor doesn't) then
the members will be constructed but otherwise uninitialized.
So, what is an aggregate class? To quote the C++ standard
(C++03 8.5.1 §1):
An aggregate is an array or a class (clause 9) with no
user-declared constructors (12.1), no private or protected
non-static data members (clause 11), no base classes (clause 10),
and no virtual functions (10.3).
In SolveSpace, we only have to handle the case of base classes;
Constraint and Entity have those. Thus, they had to gain a default
constructor that does nothing but initializes the members to zero.
After this change, SolveSpace does not contain nonfree assets.
Additionally, Perl is not required for the build.
Note that in the US, case law suggests that copyright does
not apply to bitmap fonts:
http://www.renpy.org/wiki/renpy/misc/Bitmap_Fonts_and_Copyright
Nevertheless, it was prudent to replace the asset with something
that is unambiguously free.
Almost all construction requests are lines, and allowing to
draw them as construction obviates the need to select them one
by one afterwards to convert them. Also, it removes the "not closed
contour" error message, which is a nice usability improvement.
This is equivalent to adding a constraint, then making it a reference.
The benefits are that:
* it's quicker;
* it avoids having an over-constrained system, with an associated
angry red flash and a regeneration delay.
The latter in particular is a very substantial usability improvement.
The reference distance command is useful most of the time,
but the reference angle one is also added for consistency.
The main benefit is that std::swap will ensure that the type
of arguments is copy-constructible and move-constructible.
It is more concise as well.
When min and max are defined as macros, they will conflict
with STL header files included by other C++ libraries;
in this case STL will #undef any other definition.
As a side effect, zlib and libpng are now git submodules,
based on their respective official git repositories.
This is necessary, because MinGW has a different ABI and
it cannot use the prebuilt binaries built by MSVC.
The submodules are also used for Windows, for several reasons:
* to allow 64-bit builds;
* to allow using newer MSVC, which doesn't like the prebuilt
libraries;
* to keep the libraries updated.
Some extra code is necessary to determine that the back faces
should not be drawn in red for transparent solids. It is expected
that the user will first ensure that the shell is watertight
and then set the opacity; back faces are still drawn if
the opacity is exactly 1.
The savefile format is changed backwards-compatibly by stashing
the alpha value in uppermost byte of 4-byte hex color value
in Surface and Triangle clauses. The existing files have 00
in the high byte, so RgbColor::FromPackedInt treats that
as "opaque".
This is done specifically targeting the case where an assembly
initially made on Windows is transported to an *nix machine.
On *nix, the paths will be already saved with /, and correctly
read on Windows. On Windows however / is not a first-class separator,
in particular it cannot be used in UNC-style paths \\?\ (which
are the only paths that work with Unicode).
See also:
http://msdn.microsoft.com/en-us/library/aa365247.aspx
On OS X F11 and F12 are system-global shortcuts. I could switch
them only on Apple platforms, but for consistency I decided not to.
Anyway, neither of those appeared in an official release.
This is required to avoid name conflicts with the Cocoa libraries
on OS X.
I renamed the `class SolveSpace` to `class SolveSpaceUI`, because
that's what it does, and because otherwise the namespace would
have to be called something else than `namespace SolveSpace`.
This will allow solvespace to run on pre-OpenGL 3.0 implementations,
such as VirtualBox (and possibly others).
However, VirtualBox's handling of framebuffer objects is buggy;
it tries to draw over our X window and fails to do either.
I hate OpenGL.
Apparently pbuffers are also a deprecated and unportable
way of offscreen rendering. They're not supported by
Chromium OpenGL implementation, which is what 3D-accelerated
VirtualBox uses.
This would also help a future OS X port.
Apparently GLX pixmaps are an antiquated and unsupported method
for offscreen rendering in OpenGL. Specifically this broke
software and VirtualBox accelerated rendering in Ubuntu trusty
and who knows which other systems.
This commit switches the rendering to use pbuffers instead,
while retaining all other logic. The pbuffers are fixed-size,
because reallocating pbuffers during a resize sometimes results
in segfaults in glXMakeCurrent despite apparently correct
API usage.
In principle, GTK3 is the way forward, and GTK2 is officially
deprecated, though still maintained. In practice however, GTK3
is often unbearably buggy; e.g. on my system, combo boxes
don't ever roll up in GTK3 windows. So I have added support
for both.
This required a few minor changes to the core, namely:
* GTK wants to know beforehand whether a menu item is a check
menu item or a regular one.
* GTK doesn't give us an easy way to execute something after
any event is processed, so an explicit idle timer is added.
This is a no-op on Win32.
* A few function signatures were const'ed, since GTK expects
immutable strings when converting to Glib::ustring.
fltkutil.cpp should be independent of FLTK so that it can be linked
into libslvs while neither requiring every user of the library to
reimplement these support routines nor requiring linking in FLTK.
However, don't use ssglLineWidth for UI drawing operations.
These only draw horizontal or vertical lines that don't need to
be antialiased, and thus don't require the workaround. In fact
the workaround would make them thicker than needed.
fltkmain accidentally used optind instead of optndx. optind is
defined as an extern int in glibc but not on BSD systems.
This also broke passing a filename on command line.
Writing to NULL is undefined behavior and it is legal for the
compiler to simply remove it; clang will do so. abort()
or __builtin_trap() would produce the desirable result.
abort() is used as it is more portable.
For example forward/backward buttons are present on many mouses
but are not used by solvespace. This oops() caused solvespace to
crash whenever those buttons were (accidentally) pressed.
Ubuntu enables GCC's buffer overflow checks by default. In SAVEDptr
union, the path was declared as 'char', even though MAX_PATH memory
was actually allocated. The buffer overflow check mistakenly thought
that the buffer size was only 1 and aborted the program whenever it
tried to read a path from a file.
"There was some small but annoying bugs with the FLTK port:
-cursor disappear sometimes
-not all the area of the windows (graphic and text windows) is accessible
by the mouse after a re-size
-input widget for editing constraints value are not correctly placed"
Microsoft defines an RGB() macro that at one point was compatible with our
version (returning a packed integer containing 8-bit red, green and blue
channels), but is no longer, and the incompatibility led to an awkward
situation in w32main.cpp where we had to restore Microsoft's form of the
macro in order for the commctrl.h header to compile. By renaming the macro
to RGBi()---analogous to the RGBf() macro we already define---we avoid the
hassle entirely.
The libslvs library and CDemo program can now be built by Autotools. A few
code changes were needed for this: C++ comments in C code had to be
converted, constraint.cpp required some massaging, and fltkutil.cpp needed
a stub for InitHeaps().
Place a pre-built copy of generated source files in src/built/, so that
users building SolveSpace from Git without the tools or setup necessary to
generate these can still complete the process.
Makefile.msvc: Use slashes consistently, and added rules to copy files from
src/built/ if needed
configure.ac: Check for presence of src/built/ at configure time
src/Makefile.am: Handle the generated *.table.h files together with
icon*.h; updated the source-generation rules so that the files are created
in builddir, not srcdir; added rules to copy files from src/built/ if
needed
The SolveSpace top-level directory was getting a bit cluttered, so
following the example of numerous other free-software projects, we move the
main application source into a subdirectory and adjust the build systems
accordingly.
Also, got rid of the obj/ directory in favor of creating it on the fly in
Makefile.msvc.