Commit Graph

27 Commits (7787923d059b6509db0d03d1f0ce7e785db895ae)

Author SHA1 Message Date
whitequark 8960ee365a Add a new renderer that prepares geometry for 2d backends.
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.
2016-08-01 00:48:37 +00:00
EvilSpirit 7f411d1593 Unify displayEdges and displayOutlines.
This has the following benefits:
  * Less geometry to generate; we can do both in one pass;
  * Less geometry to draw;
  * Eliminate overdraw of outlines on top of emphasized edges;
  * In future, being able to seamlessly stitch stippled lines.

The contour edges are now also drawn before emphasized edges;
this makes intersections of contour and emphasized edges look better
as the thinner emphasized edge doesn't clobber the depth buffer.
2016-07-23 22:41:16 +00:00
EvilSpirit a4a121694c Reimplement commit 0b999f4 correctly. 2016-07-21 05:45:12 +00:00
EvilSpirit 25575b14c7 Allow indexed access to triangle vertices and normals. 2016-06-30 16:40:40 +00:00
EvilSpirit 0b999f4165 Improved outline detection condition.
Before this commit, circles parallel to the camera plane caused
some edges to be randomly marked as outlines.
2016-06-30 16:39:42 +00:00
EvilSpirit 737ff51893 Skip edges with equal L/R normals when calculating outlines. 2016-06-30 16:39:42 +00:00
EvilSpirit 5791310bb1 Annotate constants passed as boolean function arguments.
This is to ensure that:
  * it is clear, when looking at the point of usage, what is
    the purpose of "true" or "false";
  * when refactoring, a simple search will bring up any places that
    need to be changed.

Also, argument names were synchronized between declaration and
implementation.

As an exception, these are not annotated:
  * Printf(/*halfLine=*/), to avoid pointless churn.
2016-05-26 12:43:52 +00:00
whitequark 1249f8496e Enable exhaustive switch coverage warnings as an error, and use them.
Specifically, this enables -Wswitch=error on GCC/Clang and its MSVC
equivalent; the exact way it is handled varies slightly, but what
they all have in common is that in a switch statement over an
enumeration, any enumerand that is not explicitly (via case:) or
implicitly (via default:) handled in the switch triggers an error.

Moreover, we also change the switch statements in three ways:

  * Switch statements that ought to be extended every time a new
    enumerand is added (e.g. Entity::DrawOrGetDistance(), are changed
    to explicitly list every single enumerand, and not have a
    default: branch.

    Note that the assertions are kept because it is legal for
    a enumeration to have a value unlike any of its defined
    enumerands, and we can e.g. read garbage from a file, or
    an uninitialized variable. This requires some rearranging if
    a default: branch is undesired.

  * Switch statements that ought to only ever see a few select
    enumerands, are changed to always assert in the default: branch.

  * Switch statements that do something meaningful for a few
    enumerands, and ignore everything else, are changed to do nothing
    in a default: branch, under the assumption that changing them
    every time an enumerand is added or removed would just result
    in noise and catch no bugs.

This commit also removes the {Request,Entity,Constraint}::UNKNOWN and
Entity::DATUM_POINT enumerands, as those were just fancy names for
zeroes. They mess up switch exhaustiveness checks and most of the time
were not the best way to implement what they did anyway.
2016-05-26 12:43:52 +00:00
EvilSpirit f33ddc94fb Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:

  class Foo {
    enum { X = 1, Y = 2 };
    int kind;
  }
  ... foo.kind = Foo::X; ...

and convert it to this:

  class Foo {
    enum class Kind : uint32_t { X = 1, Y = 2 };
    Kind kind;
  }
  ... foo.kind = Foo::Kind::X;

(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)

The benefits are as follows:
  * The type of the field gives a clear indication of intent, both
    to humans and tools (such as binding generators).
  * The compiler is able to automatically warn when a switch is not
    exhaustive; but this is currently suppressed by the
      default: ssassert(false, ...)
    idiom.
  * Integers and plain enums are weakly type checked: they implicitly
    convert into each other. This can hide bugs where type conversion
    is performed but not intended. Enum classes are strongly type
    checked.
  * Plain enums pollute parent namespaces; enum classes do not.
    Almost every defined enum we have already has a kind of ad-hoc
    namespacing via `NAMESPACE_`, which is now explicit.
  * Plain enums do not have a well-defined ABI size, which is
    important for bindings. Enum classes can have it, if specified.
    We specify the base type for all enums as uint32_t, which is
    a safe choice and allows us to not change the numeric values
    of any variants.

This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-25 07:17:14 +00:00
whitequark e2916e3e4a Factor in SOutlineList::FillOutlineTags. 2016-05-25 03:22:54 +00:00
whitequark 20d87d93c5 Add const qualifiers to functions where trivially possible.
This will allow us in future to accept `const T &` anywhere it's
necessary to reduce the amount of copying.

This commit is quite conservative: it does not attempt very hard to
refactor code that performs incidental mutation. In particular
dogd and caches are not marked with the `mutable` keyword.
dogd will be eliminated later, opening up more opportunities to
add const qualifiers.

This commit also doesn't introduce any uses of the newly added const
qualifers. This will be done later.
2016-05-25 03:22:54 +00:00
EvilSpirit bbca4cc224 Rewrite declarations of form f(void) as f().
In C++ there is no difference and newly added functions are all
declared as f(), so this brings back consistency.
2016-05-20 12:43:20 +00:00
whitequark ad4a204edf Replace all oops() checks with ssassert()s.
This includes explanation and context for non-obvious cases and
shortens debug cycles when just-in-time debugging is not available
(like on Linux) by immediately printing description of the assert
as well as symbolized backtrace.
2016-05-20 12:38:30 +00:00
EvilSpirit a75bf6e216 Fix incorrect condition ordering that causes a crash. 2016-05-04 04:34:03 +00:00
EvilSpirit f5d8b1dc6b Implement missing parts of 09f59ddb.
This caused no crashes, but some extrusions resulted in a wrong mesh.
2016-05-04 03:21:12 +00:00
EvilSpirit 24fc65a71c Allow rendering solid outlines using a distinct style.
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.
2016-04-15 21:53:08 +00:00
EvilSpirit d1a2eb6d18 Allow rendering hidden solid edges using a distinct style.
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.
2016-04-15 21:53:08 +00:00
EvilSpirit d55300232f Don't generate each edge twice in MakeCertainEdgesInto.
This messes up edges when they are rendered stippled, and
unnecessarily makes exported files bigger.
2016-04-15 21:53:08 +00:00
EvilSpirit 1bf7777815 Only export sharp edges of the triangle mesh.
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.
2016-04-15 21:53:08 +00:00
EvilSpirit 7e6a11c958 Refactor SKdNode::FindEdgeOn.
Extract output parameters into a separate structure.
2016-04-15 21:53:08 +00:00
EvilSpirit 09f59ddbc0 Get rid of if(!this).
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.
2016-04-15 06:11:03 +00:00
whitequark 29ad1acdfe Enable and mollify -Wunused-variable.
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.
2016-02-14 14:29:47 +00:00
whitequark 45f056c852 Replace all ZERO and memset with C++11 brace-initialization.
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.
2016-01-13 06:45:16 +00:00
whitequark 28166e6200 Use C++ std::{min,max,swap} instead of custom ones.
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.
2015-12-28 21:37:06 +08:00
whitequark 75a3936b64 Add support for transparent solids.
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".
2015-07-10 15:59:12 +03:00
whitequark c5364fe7a8 Trim trailing whitespace. 2015-07-10 15:59:11 +03:00
Daniel Richard G 0a24cf40f0 Moved most of the source into a src/ subdirectory
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.
2013-11-19 18:17:32 -05:00