Project Home

Daily Log

I'm going to keep a daily log throughout the summer, and I'll keep it updated here in case anyone finds it interesting.

May 27

Today I added got the CurveMapping interface element added to the modifer UI when the custom profiles checkmark is added. What took most of the time was figuring out all of the places I needed to change to make this happen. It makes sense looking at it afterwards, but the changes I had to make were quite distributed around (See Piping Data in notes). I learned a fair amount about the structure of the code doing this. There are still issues I need to solve with getting the new properties into the tool, especially the profile drawing interface.

I'm also starting to look more into where to add the functionality to the CurveMapping code that I need to. (The drawing and sampling of a non-function). Once I do that I'll be able to get this data into the calculate profile part of the operator (and solve the issue of half of the profile being done at once, that's still an unknown at this point).

May 28

I had to drive back home from Vermont today, so I didn't get quite as much time I thought. I focussed on creating a method for sampling the CurveMap curves along their path rather than along the X coordinate today. For now I am using linear interpolation rather than curves though. I basically need to calculate the total distance of the curve's path and then travel down it and record the position (both X and Y now!) for the segment.

The existing CurveMapping code evaluates this once and stores the result in a table so it doesn't have to recalculate it, and I will need to do this next.

I'm just testing this functionality in the bmesh_bevel code for now. Although I've started discussing how to get this data incorporated in the bevel process, for now I'm focussing on creating and displaying it.

Hopefully I will be able to finish up the two types of sampling tomorrow, and then I'll look at connecting the points in index order rather than in order of X.

May 29

I've finished the linearly interpolated sampling of the CurveMap, and by removing sorting from the curvemapping_changed function the profile curve can be properly not a function, but it doesn't draw correctly. I'm finding that there are so many parts of the curvemapping code I have to change that I'm rethinking my plan of putting my code for the "Path_Mapping" code in there with it. Here are the things I have to change from the original curvemapping code to get to my profile editor:

  1. The structs I have to store the total length of the curve and the amount of segments to sample it with. And the tables also need to be twice as big because they need to store X and Y values for each sampled location.
  1. Evaluation Instead of returning a single float, evaluating along a profile returns the 2D coordinates of a point along the path.
  1. Drawing The evaluation for drawing currenty assumes there's only one Y value for each X.

There are also quite a few features that aren't needed from the CurveMapping code: extrapolation, the specific color mapping features, and the generality of not specifying the 0 to 1 clipping range.

In addition to finishing up the simple sample case, I also started to get the sampled data into the Profile struct in the bevel code. I'm figuring out the first simple cases that I can address first.

May 30

Today I finished getting the sampled info into the ProfileSpacing struct. That struct contains the 2D locations of the profile's points before it gets transformed into 3D on top of a plane. Unfortunately I think this means I've completed most of the more straightforward part of using the profile information in bmesh_bevel.

I also spent way too long today dusting off my GDB knowledge diagnosing some stupid seg-faults that I caused with some typos and another silly mistake. It's all part of getting up to speed on a new project, and it'll be faster in the future, but it still feels stupid in retrospect.

Next, I could either focus more on getting the profile UI widget drawing fixed out, or see what I can do with this profile-spacing info in the simple weld cases I've talked about.

May 31

Today I focussed on laying out where my changes will need to go in bmesh_bevel.c. I've formed a plan for getting bevel cases (like the weld case where just two edges meet) to work with custom profiles while keeping the rest of the modifier working while I work on the project. I'll store the custom profile 2D coords alongside the normal profile 2D profile coords in ProfileSpacing. Because I have both of those, I can call calculate_profile_custom instead of calculate_profile in cases that I'm working on which will use the custom bevel profile when it finds the 3D coords of the profile.

After that I started to try to find where the cases I will consider first are in the code, and figure out what the execution path is that leads up to them. First I am going to consider the case M_NONE, the weld case. I need to figure out where calculate_profiles is called along the path that leads to that case in order to find where to change it.

For a change of pace I also started to write the function to create the table of segment locations along the path, but I am going to need to think a little more about generalizing it before I consider that finished.

June 3

Today I got the first visual results of the custom profile in the weld case, which is very exciting! It's still symmetrized by the existing code, and I'm not sure it's even behaving correctly, but moving the points in the UI moves the beveled vertices, so that's cool.

I didn't write much code today though. I mostly went through the build_vmesh code, looking at the weld case specifically. My process is generally going through and writing down a bunch of questions, then looking through the code again trying to answer them. I also solved some seg faults that came up with some of my smalelr changes.

Over the weekend I thought of a method to generalize creating the sampled table. I wrote it but I didn't pursue testing it because I think the final implementation of the curve widget is a little too up in the air to pursue optimizing it at this point.

June 4

I got the terminated edge (n_gon end version) case working today, which is the first time I've been able to actually see my custom profile properly in the bevelled mesh. This makes it clear that I need to focus on getting the drawing code working better quite soon.

I would have liked to get the weld case working, and I think it did work a couple times in my testing throughout the day, but right now when the segment count goes up all of the profile points bunch up to one location on one side of the profile.

Luckily, so far these changes haven't amounted to much more than feeding the new profile point locations to the profile vertex creation code, and disabling / simplifying some features that are unique to the sampling of the superellipse from the regular profile.

The next problem I'm going to need to tackle for these cases is orienting all of the profiles in the same direction, chance already isn't quite good enough. I'm going to need to find a way to calculate chains and cycles of beveled edges and a way to store which side of each BevVert / VMesh is the top, and make it consistent.

June 5

Today I spent a fair amount of time debugging the problem I mentioned where the profile vertices would bunch up on one side of the profile. It turned out that the custom profile case needed to get the profile from the Profile struct, because it wasn't done that way otherwise. Now the vertices get placed at the correct location. I find that when I decide to start testing and debugging a problem rather than just looking around in the code it takes longer to find the solution. But I do think I learn more in the process.

Now the weld and terminal edge profiles are placed properly, just with the wrong orientation sometimes. So I also started to think about how to properly implement the process of finding consistent orientations. As usual, once I start to write about it, I start to understand it and the intuition for the solution becomes a lot clearer. I posted about this in my DevTalk thread for feedback if anyone has any, and I'm looking forward to starting to implement it tomorrow.

June 6

I started constructing the code to regularize the orientations of the profiles today. I started with a comment structure showing the steps the code will have to take. And of course I had to make a few changes to how it will work, just like always. I decided it's better to travel from EdgeHalf to EdgeHalf, because those are the elements that are actually beveled, and they have pointers directly to the two BoundVerts from which the profile could start. There are two parts that I am still figuring out how to best solve.

One is traveling across a BevVert to the next EdgeHalf. The case where there is only one other beveled edge leaving the vertex is simple, it's just a weld and the code will travel down that next edge. But if there are more beveled edges coming into the vertex it becomes more complicated. They might all even form the same angle with the edge we're traveling from. I haven't decided how to manage this case where they form the same angle, except maybe arbitrarily.

The second part is how to actually propagate which side of the EdgeHalf the profile should start at. My only idea here is checking which of the two BoundVerts connects to the last starting BoundVert. To implement that I just have to work my way back across the new boundary edges, and hope that they have already been built.

It's fun to think about these problems, but I do hope this method ends up working out.

June 7

Today I continued working on my implementation of **profile orientation regularization** (which is actually getting much faster to say). The part that actually travels down the beveled edges should be finished, although I'm sure it will cause some segfaults before I really finish it. The only part of this that isn't finished is the part that marks the BoundVerts as profile-beginning or profile-ending edges. This is a tricky problem. I've thought of a solution for one of the cases, but it relies on the boundary geometry being built and connected up, and I'm only hoping and guessing that that is true.

I wrote up a section about this in the notes document: "Passing Along the Choice of BoundVert for Profile Start." It's very helpful more me to lay out the problem like that.

I've spent two and a half days without even compiling code. It's maybe not as exciting without visual progress, but it's great to be so immersed in solving a single problem.

June 10

Over the weekend and today I finished the first draft of the profile orientation regularization code and started to test it. After thinking about my convoluted method for passing on the correct profile orientation I realized that I was hugely over complicating the issue. The fact that really simplifies it is that every time you move from one EdgeHalf to the next, you flip whether you are moving into or out of a BevVert. And because the left and right sides of an EdgeHalf are defined relative to the BevVert, they switch off every time. So the orientation just needs to reverse every time!

I tested by drawing a sphere with DRW_debug_sphere at every profile start BoundVert. After fixing one segfault, the code did mostly what I expected-- the profile start stays at the same side of the beveled edge. There are some issues, and the code doesn't execute exactly how I expected, so I'll need to spend some time improving it though.

Today I also made the weld case use the new profile orientation information. If the first of the two BoundVerts it comes across isn't the start BoundVert, it switches them, that simple!

June 11

I don't have much new to report from today. I'm testing the code I wrote for traveling down chains and cycles of beveled edges, and like I said before the results are mostly good, but it's not working how I expected it to. My test scene has one long chain of beveled edges, so I would only expect the traveling code to run once-- it should visit everything the first time. But instead it only visits one edge each time. The function that gets the next edge to visit is not working in the "into BevVert" case.

I should probably make it a rule that it takes the same amount of time to debug code that it does to write it, it would probably help me plan. Luckily I was visiting with my brother and he was interested so I could explain my code's situation to him to make it more enjoyable. I hope I can fix this problem soon, although that unearth another problem.

June 12

Today I fixed the first problem I came across with the traversal for the orientation code. I disabled all of the iterations except the first, and then fixed issues and tested things out until it traveled all the way along the chain of beveled edges I've been testing with. There are still issues with the side of the EdgeHalfs that it assigns as the start, but at least it travels around properly. It was sort of slow debugging today, but every day I get better at working with the bevel code, and I figured out how to draw debug spheres on vertices, which makes testing much quicker.

June 13

I had a shorter day today, but I still made progress on the process that marks the BoundVerts as profile starts. It now marks the same side along a path properly in my test cases. I started to look into using this information in the terminal edge case. I'm not sure yet though whether the profile vertices in the terminal edge case are created in the same area as the profile vertices of the weld case. I hope to be able to switch the BoundVerts based on which is the profile start the same way I delt with the weld case.

I've started thinking a bit about how to deal with the >2 beveled edges case. I think I will probably want to interpolate between the profile of every boundary edge with weights based on how far the new vertex is from each boundary edge.

I also discovered that it's possible to create geometry outside of the 0 to 1 region, outside of the profile. It's great that it's disabled by default, but by disabling clipping and zooming out you can move the profile geometry further than you can by default. It's awesome to have the option to do this, it will probably be pretty useful in some situations.

June 17

Today I spent a while looking into how to get the terminal edge case to use the marked profile orientation. This is tricky because the profile for a terminal edge is part of the boundary, which is created before the orientations of the profiles are regularized. This necessitates a method to adjust the "boundary arc's" vertice's locations after they are created.

I also looked into how to implement the drawing for the profile creation widget. The first idea I have for drawing the dark area under the profile is to start drawing light from the top then travel down the widget's height, switching to dark after hitting any line between two points, then switching back and forth between colors every time it hits a new line.

In order to implement this I have completely separate the new "profile_path" code from the original "colortools" code, which is proving to have effects in multiple areas of the code, the drawing, the input, and others.

June 18

I finally figured out the best way to fix the orientations of the terminal edge profiles. After trying out a bunch of options, I settled on something quite simple. If a terminal edge profile is being created with the wrong orientation, it recalculates the profile positions. I added a "reversed" option to calculate_profile_custom that flips the vertices across the y=x line, and then the vertices are placed in the opposite order. This is fix is simpler than I expected, which is great!

I've also been separating and changing the CurveMapping code into new ProfileWidget headers and files. I've created three new files for this: DNA_profilepath_types.h, BKE_profile_path.h, and profile_path.c. I'm not certain these are the best names, but I am confident that completely separating the profile widget code from the old CurveMapping code is the right choice. So much has to change for the profile functionality that it feels more harmful than helpful to keep them together.

  1. The points are not sorted by their X values
  2. The drawing has to be rewritten to take into account the non-function nature of the profiles vs. the direct mapping of the curves.
  3. The evaluation also has to be rewritten to return both X and Y values as results. This is already complete for the linear case.
  4. All functionality relating to color management becomes unecessary.
  5. It's not necessary to have more than one curve (profile), which simplifies some functions.
  6. The presets will need to change.
  7. Extrapolation is unecessary and can be removed.

Here I've also basically written myself a todo list for the next few days. I think the hardest parts will be writing the drawing code and connecting the interface callbacks back up to the new implementation, they will both necessitate venturing deeper into Blender's UI code.

June 19

Today I've been working on fixing up the code I reused from the curve editor. I've removed a lot of it and converted it to use the profile editor code instead. There are so many places in the interface code to change. I've been making fast progress, and I think early tomorrow I'll be ready to try compiling it and start fixing whatever errors come up. Then I can start to implement the improvements I mentioned, mainly updating the drawing code.

June 20

Over the past day or two I've modified 30 different files while creating the ProfileWidget code for the custom profile input. The net change is +1500 lines so far. Mostly I've started by duplicating the code associated with the CurveMapping curve editor. Then I strip out unecessary functionality, which in some cases removed most of the new code. After that I moved through the new code fixing errors and switching to the new use case, which also reduced the complexity of the new code a lot.

I wanted it to compile by the end of the day today, and I've gotten that far! Now I'm going through the process of finding more and more esoteric SEGFAULTs-- currently I'm fixing an issue where the total number of points in the profile path is -32768. I wish I knew a way to write code without creating those kinds of issues, but then I suppose I'd be finished with my project.

June 21

At first today I focussed on fixing crashes that came up in the transition to the new ProfileWidget code. After fixing a couple, including the incorrect total point value I mentioned yesterday, the widget is mostly stable. I then did some work on the UI for the buttons above the profile editor, making them look more in line with more recent 2.80 UI (and better in my opinion).

After spending a while with the widget's drawing code, I understand how it works well enough to make the changes I need to. I started to implement the profile color fill algorithm I've described before, but I've been dissapointed by how inefficient it seems, and I think I thought of a better solution. I'm hoping to be able to use an existing triangulation algorithm to fill the "polygon" of the custom profile with a darker color. My original method would have been O(x_width * nlogn) (where n is the number of points in the table), and it looks like a triangulation algorithm would at least drop that x_width term, which could be very helpful. I'm hoping to get feedback on how possible this over the weekend.

June 23

I worked on the ProfileWidget a lot over the weekend and I actually finished what I had planned for the next week today! I finished the fill of the profile area with the triangulation method. I wasn't sure if it was going to work, and I had some really cryptic errors on the way, so I was really excited when it worked! It works really well, and you can't see any overlap between the triangles which was one of the things I was worried about. It looks a bit odd with quadrant 1-4 point positions when clipping is turned off, the bottom-right corner could move down to the display's corner in that case.

I also implemented a new insertion algorithm that uses the minimum line segment distance to choose the index of the new point after a fair amount of experimentation for the best algorithm.

And finally reading and writing the bevel modifier's profile widget is working! So we can save and load files with these features.

Overall I'm really happy to have that all done earlier than I expected. It means I can hopefully make progress on a couple things this week: 1. Begin tackling the ADJ vertex mesh generation. 2. New table generation for the profile path that doesn't use an X-Y mapping. 3. Fix profile sampling with "Sample only points" turned off.

June 24

Today I mostly moved back into the bmesh bevel file. I started to experiment with the remaining cases I haven't tackled. First, the pipe case, which basically reuses the profile again and again for each vertex along the straighter edge. Right now it snaps to the superellipse function, so I tried to convert it to snap to the custom profile, but I failed really spectacularly! I think I have the right idea-- the profile is moved along to each point and the point is snapped to the closest line, but right now all it does is give the mesh huge spikes and crazy geometry!

I also found every instance of calculate_profile and made it use the custom variant in the custom case. It's interesting to see what it does, and it's definitely closer, but it might be a long path to get it to work.

June 25

After causing a bunch of crazy errors in the bevel vertex mesh creation yesterday, I decided that I needed to understand the overall process better. So today I added print statements to most of the ADJ vertex mesh generation functions to get a better picture of the process that's used to bevel these situations. After getting a better understanding of what's going on I made some simpler changes -- using the custom profile instead of the superellipse profile, disabling snap_to_superellipse and others. Mostly this totally ruined the vertex meshes, but it has to get worse before it gets better! Right?

Somewhere in the process I caused a strange segfault that I've been working on solving for a while.

June 26

I finally solved that segfault I was working on yesterday! It turned out to be a pretty stupid mistake of disabling the free block at the end of the bevel function which was why it was causing an error in a different place in Blender. With that solved I started to work a bit more on the vertex mesh creation. I'm still in the phase of understanding how the ADJ pattern is already created, so it's slow going.

I also spent some time getting the profile widget more feature complete. I added:

  1. A reverse button that flips the position and the order of the profile points. This will be the way to flip the orientation of the bevel profile.
  2. A functional preset selector with three presets built in for now.

Working on the profile widget is sort of a way to procrastinate on the vertex meshes, but I'm still feeling good about the progress I've made there.

June 27

I'm still working on the vertex meshes. I mostly made progress today in understanding what's going on already and thinking about plans for my implementations. There are three cases I need to solve, one is the "cube corner" case, another is the "pipe" case, and the last is the general ADJ pattern case. I think I have general ideas of how I want to solve the first two.

First, for the "cube corner" case, I would like to keep using the general subdivision method that's already used. Right now though the code snaps to the bulge created by the profile radius. I'd like to either just remove that or replace it with something that moves closer to sampled profiles depending on how close it is to each one, which would tie in to my general ideas of how to deal with the general case.

And second, for the "pipe" case, it should be possible to use a somewhat simpler solution. I would like to try recalculating the profile at every ring along the line of the "pipe" and just use the profile at that location. This depends on a couple other assumptions being true, but it seems like it might work well.

The general case is much harder. Apart from some unguided subdivision in the vertex mesh (which probably wouldn't actually be that bad in most cases), I don't yet have specific ideas of how to deal with it. I'll probably want to progress more with the other cases before I try to make concrete plans here.

June 28

Howard answered some questions I had about the vertex mesh creation and related code today. He wrote a lot of really helpful explanations, so I've been going over them and making sure I understand everything he wrote about. The idea of the canonical indexes for VMesh vertices was a particularly important thing I finally think I understand. Because there are multiple ways to index the same vertex there is one proper / canonical way.

After clearing up some of these confusions I started to make a plan for how the best way to tackle the VMeshs, what I'm calling "Decaying Profile Influence." I would like to try it out manually for a profile with an overhang before I settle on it though.

July 1

I spent the morning finishing up some experiments I was doing over the weekend trying out different methods for VMesh creation. I enjoy the process of communicating this stuff, and it's great to get people involved. The consensus seems to be that the ADJ grid and the Boolean options are good, and having both of them would be the best solution. Given that I almost have the mesh ADJ grid working, I'm considering tackling the boolean method too. Then I'd be able to make an option for which one was used. It could even go in as a miter option!

I'm wary of taking on too much with not enough time left though; judging by how it was pretty tricky to get the boolean option working manually, I doubt it will be quick to implement. But it seems like a great solution for some of the more geometric profiles.

I wanted to lay out the other big things left to do to help prioritize:

  1. Get the profile widget into the bevel tool menu. I should only need to pass the pointer through the BMesh slot.
  2. Fix memory leaks. The process of copying the old profile widget crashes when I enable the modifier's "freeData" function.
  3. Update profile widget table-building. I've figured out how to do this and I don't think it will take too much longer.
  4. Fix profile orientation next to impassable BevVerts. Just a bug that I think might take a bit of time to fix.
  5. Documentation and cleanup.

Also today, I've made some progress on the profile widget's table creation, and I made a bit of progress for custom profile ADJ VMesh creation.

July 2

Today I made some decisions about what I wanted to prioritize for the rest of the summer. I decided to focus on the ADJ method and the "cut-off" method that was suggested on DevTalk for now for creating VMeshes. The boolean method is such an unknown that I don't want to jeopardize anything else to make it work. It's definitely still possible that I get to it, but I'd like to get through my backlog first.

To that end, today I knocked one of the big items off of the to-do list. I fixed **#2**, the memory leak from the bevel modifier and fixed saving and loading bevel modifiers in the process. I also merged the ProfilePath and ProfileWidget structs-- I can't think of a situation where a given widget would need more than one path. I also made a fair amount of progress toward getting the profile widget into the bevel tool(which now works!). The hard part will apparently be freeing the widget when I'm done with it, but I'll figure that out when I get there.

I have to add a couple more items to my big things left to do list though:

  1. Add "harden normals" functionality. Set custom normals for the profile faces using the curvature of the profile.
  2. Add symmetrical profile drawing. For now I don't want to commit to making another VMesh method for this, but I've received a lot of requests for a symmetrical option and this would be an important step toward that.

July 3

I spent a while today working on getting the profile widget in the redo panel. I really feel like I'm guessing when I start using the RNA system, and to combine it with the bmesh slots system makes it even more confusing. I think I may have solved the problem of how to get the pointer to through the RNA function (editmesh_bevel.c) to the bmesh system (bmo_bevel.c), but I can't tell yet, because I can't figure out a way to actually draw the profile widget in the redo panel. There's no way to access a UILayout pointer from the mesh tool that adds the other properties, and I need that to call the profile widget template. I've added the other options though!

Anyway, I'm not familiar enough with the way the redo panel is created and so far it hasn't been an easy thing to locate in the code. With so many things left to do, I decided to move on to something I can do more efficiently. I started to work on updated sampling for the profile. I'll use the same sampling for making the display table and the evaluation for finding where the profile points should go, which is great because it will simplify my code. There was a lot of discussion on DevTalk about the best way to do this. It might be nice to add more options in the future, but I think I chose a method that's a good compromise between the different requirements.

July 4

I got the new sampling algorithm mostly working! Writing it was a lot of fun in the morning, but it became quite a slog in the afternoon when I had to fix all of the bugs I also added-- plenty of incorrect calculations, corrupted memory chunks, and other segfaults. I used the profile widget as a way to test the new algorithm, so it looked pretty crazy when it didn't work. I'm happy with where it ended up though. I like how general it is and how it has a few different use cases.

There are still some things I need to fix though. I think the reduced version of the bezier handle calculation that I copied over from colortools.c makes some assumptions for the X direction that I'll need to figure out. Right now it looks like the handles aren't in quite the right place. Maybe I'll start again from the curve.c code and reduce it myself. Another thing to fix is that I didn't realize the bezier forward differencing included the starting bezier point, so I'll have to fix that.

July 5

I enabled the new sampling for the bevel profile curve this morning and it's working well. I think it will be important to have the option to disable the extra samples for straight edges though. I spent most of the day fixing bugs and crashes that I found or created when I made this change. It was slightly frustrating but it should be pretty stable now. It's fun to use!

I also flipped around the X profile orientation. (And solved all the bugs that came up there). It's nice to have a clear list of what I can do next. I think next I'll add the option I mentioned above and then move on to other tasks.

July 7

Over the weekend I spent some time working on creating an option for whether to sample the straight edges between two vector-handle control points. There's some (relatively) complicated logic in the code that determines how many samples to give to each edge. First I give one sample to all of the straight edges, just so that their start point is sampled. Then I ask-- out of the remaining samples, how many can I give to each curved edge if I split them up evenly? I assign those and then distribute the (still!) remaining samples to the most curved edges. Then the sampling process happens and the locations are returned. It's fun code but it took a while to debug.

With that done I'm almost completely happy with the sampling process. I may need to test the "don't sample straight edges" case a bit more, especially the last step of sample distribution process I just described, but once I do I think most people's needs will be filled. I'll want to get feedback on that though, because it could be that another method would be really important to some people.

July 8

I couldn't work quite as much today, I was switching locations again on my quest to live somewhat nomadically, and the trip and getting set up takes longer than I expect. And the work I did do was a little bit frustrating too. I chose one of my 8 remaining items on my to do list, the profile widget in the redo panel. After getting some help on the chat I set up a custom drawing callback that will now draw the redo panel for the edit mesh bevel operation.

But I haven't been able to get there yet because of an error I've been running into with the rna system when I try to add the ProfileWidget pointer to the operation's properties that leads to a segfault later on when the operation is run.

".prwdgt": only during preprocessing.

I have to say I feel very lost whenever I try to do anything a little more complicated than the basics with the RNA system. It seems very cool, but I wish it was documented better. There are so few comments in the RNA API files! I've pretty much resorted to searching around the codebase for similar examples. I'll probably ask for some help tomorrow morning. I know I haven't properly set up and initialized the pointer, so that may be it.

July 9

When I asked on Blender.Chat about drawing the RNA pointer issues I was having, Jeroen Bakker suggested using the global ToolSettings struct to store the ProfileWidget. This makes the ProfileWidget available everywhere from the scene's context. This is great because it gets around the issues that Howard was having with freeing pointers after they're used by the tool, and it makes storing and reusing the widget easier by pretty much bypassing the RNA system.

So I implemented that and got the widget's profile view into the redo panel. It's awesome to have it in the tool and it's fun to use! The issue is that all of the widget's other buttons are in the UI Template code, and the whole premise of that code is that the ProfileWidget is in a RNA property! I thought that this would make this solution inviable, but it turns out that everything inn the ToolSettings struct has an RNA property too, so I added that and it works well!

There is one strange issue where the "Use Custom Profile" checkbox shows up a second time when the first one is enable though, it's quite weird.

July 10

Today I fixed the problem with the orientation of single segment bevel chains. It turned out to be a very simple fix, much easier than I expected. I basically just had to change the orientation assigned to the first edge visited.

I also moved the "Sample Straight Edges" option from tbe bevel operator (modifier and tool) to the ProfileWidget. I'd imagine that anything using the widget would probably want this option, so putting it in makes it more modular and hopefully more useful.

In the place of the "Sample Straight Edges" property, I added a "Vertex Mesh Method" property to the bevel operator. This will let you choose between the ADJ and cut-off methods, even in non-custom profile cases. In the future you could hopefully also select the boolean method and others. For now the cut-off method is just a hole though. It should be a fun project to implement it!

July 12

Today I worked on laying out the algorithm for creating the cut-off vertex meshes. I think I've mentioned before that this is always a really fun process. The description of how it will work then becomes most of the comments for the code, so I think it ends up helping the quality of the code's documentation.

The algorithm I finally came up with finds the direction of the "vertical" into the mesh, and puts a corner vertex down that direction from each boundvert by the height of the transformed profile. If it's a 3-way intersection it checks to see if they're at the same spot, but otherwise it always makes the center face and also the cutoff faces for each profile by using those corner vertices. It ended up being a lot simpler than I thought! (At least the algorithm, not totally sure about the implementation yet)

July 15

Today I worked on the first draft of the cut-off method vertex meshes. The trickiest part is the problem of how to actually get the data into the bev_create_ngon function, which creates all of the faces in the bevel code. The poly method (simple triangles for the one segment cast) uses BLI_arrays to accumulate vertices, whereas the ADJ mesh is built by accumulating the vertices in NewVert structs and storing them in the VMesh struct, then later creating the Ngons/quads directly from those. There are pros and cons to both methods, but I think the former is better, because there are only a few extra verts in the vertex mesh. I don't think it's worth complicating the indexing of the VMesh struct to add them in.

July 16

Today I finished up implementing the cut-off method code. I'm still having trouble getting the data into the face creation function, so I'm starting to debug that. When I get it to stop crashing I'm pretty sure there will be more things to fix, but I'm pretty confident that the big ideas are right.

I also worked a little bit on finishing the updating of the ProfileWidget Python API. Now I'm pretty sure the only thing to do there is update the evaluation functions to return 2D vectors instead of just a float. I just need to find an example of where that's already done somewhere and it shouldn't be too hard.

July 17

I'm discovering again that the implementation of a new algorithm takes *much* more time than it does to concept it! I've resolved the crashes but the vertices are placed in crazy locations, and those that are correct (the profile vertices) are doubles because I'm creating a new BMVert every time I add a vertex to a face for now.

I really need to properly understand the whole process and reasoning behind first creating an array of NewVerts and then creating the BMVerts. I think it's mostly a quicker way to find the right vertices, so I don't think it would be necessary to use the same process in this situation because there are so few of them, but I think I will anyway. The whole setup is there anyway, and the abstractions are useful so I might as well use them.

July 19

Today I *finally* got cutoff method working. I'm now filling the VMesh NewVert array and then creating the BMVerts, sharing them between some of the NewVerts. I'm only using a few of the ADJ pattern indices, just 2 on the second ring for each boundary vertex. This whole process makes a lot more sense now that I've implemented something like it myself, but it took a lot of trial and error to figure out, and I had to fix a couple very silly crashes I created in the process.

One thing I still need to figure out is the direction of the edges for each profile's corner face. I was using the (ready?!) average of the cross products of neighboring profile's normals and their horizontal directions, but that wasn't working out very well. Now I'm just using the opposite of the normal of the face closest to each boundvert. This is ALSO not right, because it results in cutoff faces that aren't quite planar. I just need to figure out the math for the right direction at this point, everything else is in place. That which will probably involve finding the direction of the edge that's the intersection between the two profile planes.

July 20

Today I mostly worked on: 1. Getting miter options to turn back to the default "sharp" method when the cutoff vertex method is enabled. 2. Adding a second ProfileParams struct filled with regular (non-custom) profile data for the miter profiles when miters and custom profiles are used together. It felt like a nice break to focus on something easier than the past week, and this knocks another item off the todo list-- that's always nice. I should probably think about a better way to disable options though. Just making them *not work* isn't really the best solution. Graying them out would probably be better, but then you sort of run into a network of dependencies with the options, and that might get a bit too complicated.

July 22

Today I decided to actually do a first pass on the implementation of the pipe ADJ mesh case. The logic isn't too complicated-- it attempts to reuse the profile at each vertex in the mesh by intersecting the original profile with a new plane at the current vertex's ring in the VMesh.

It works, but only for a portion of the vertices in the VMesh, which suggests problems with the vmesh NewVert indexing. It could be that I shouldn't be adjusting the position of a "non-canonically" indexed NewVert. Although I'm not certain about that, because theoretically If the code works at some vertices it should work everywhere, and when I use the same code with the original for loops (original indexing) it also only works properly for a portion of the vertex mesh. It's not quite the type of thing I know how to debug though. I'll seek some feedback on it.

July 23

Today I worked more on debugging the pipe vmesh case. I got to a point where I'm sure that it's calculating the right locations for all of the vertices, but it's either not using the new locations properly or they aren't being put in the right spot.

I also started going through the "HANS-TODO" markers resolving the problems or making sure they were either not problems or already solved. I started with 58 and I've gotten it down to almost 50 now. As I go through I'm finding that a lot of stuff is looking pretty close to finished, which is a great feeling. The problems I have left are the more esoteric, nuanced bugs though. Luckily I have a lot of debugging code that should still be useful, and I don't think any of the bugs are showstoppers, but they might be a bit tricky to solve.

July 24

Today I worked on a number of different things. I started by looking through the feedback from Howard on the pipe ADJ mesh with a custom profile. I fixed some of the things he mentioned, but I'm still not sure about the indexing issue (at least that's what I think it is). There are also the 3-way pipe cases where the pipe profiles are diagonal and meet at the same BoundVert on one side. I still think getting the original position of the vertices before snapping with "adj_mesh" is probably a good way to go, but it might not work in that 3-way situation. It's sort of funny that the pipe case is almost harder than the general ADJ vmesh case.

July 25

I'm also making progress on the TODO comments. I've got it down to 44 and solved some things that I had been putting off. There are still some issues with the sampling, but now it shows a preview of where the bevel's segment samples will go in the widget itself in addition to the control points. It turns out the bevel code can't affect the ProfileWidget that's displayed in the UI because it has a copy of it, not the original. So I have to give the UI ProfileWidget the correct number of segments in the Python interface code. That's the first test of widget's API and it worked the first time, which is nice.

The versioning for old bevel modifiers without a profile widget is also working now!

I'm down to 31 TODOs at the end of the day, but I caused a new bug in the process with deleting objects with bevel modifiers and enabling custom profiles. I'll have to solve another TODO with sampling fewer samples than control points to fix the second. I guess when I fix problems I always tend to add more! But overall I'm making good progress getting rid of the backlog! I'm just happy I actually kept track of it or I'd be wasting a lot of time looking around for these things.

July 26

Today I continued the process I've been working on the last few days, working on the smaller TODOs scattered throughout the code. I'm down to 21 now. The remaining changes are mostly smaller bugs I still need to fix. The biggest group of them is probably some of the weirdness with the sampling code and how it's used by bevel.

There are only a few weeks left now, especially because I'm going to be away the last week. I'm starting to prioritize the things I think I need to finish this summer and I'm saving some of the less critical stuff for afterwards.

July 29

This morning I started looking into a bug I caused earlier where dragging the ProfileWidget points doesn't update the modifier. I don't think it's an issue with the widget itself, because dragging the points still updates the tool. It's also strange that some of the buttons in the widget *do* update the modifier! I don't see anything related to updating in either the tool or modifier RNA definitions though, so I'm not sure how much difference there can be there.

I had a shorter day today, but I also resolved a couple more TODOs. I'm down to 18 now. I also settled on another method to try for the pipe case. I'm going to use the regular "canonical" indexing of the mesh verts and use them to find the corresponding indices of the pipe profile mesh verts. Then I'll interpolate between the two based on which ring relative to the pipe profiles the current index is. It's going to be some tricky logic to do the translations between boundvert indices, but hopefully I'll understand the ADJ indexing very well afterwards. And I only have to do it in two cases-- the pipe case has a 3 beveled edge and 4 beveled edge case.

July 30

This morning I found the bug that was causing the widget to not update the modifier this morning. It was just this line of code had moved to the wrong place in the buttons layout code: UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);

I also finally got the pipe case working, but only when it's a 4-way intersection. The 3-way intersection is much more complicated because the triangle area between the two profile planes is diagonal, so there has to be some more interesting math. But I think I can get that finished tomorrow.

July 31

It's nearly August! And I finally finished the pipe case. I'm actually really happy with the topology it creates. I thought it might be pretty weird, but I think maintaining quads throughout the whole vmesh is much more useful. And it doesn't waste polygons like the "triangle fan at the end" method would have.

It took a fair amount of thinking / trial and error to figure the indexing and interpolation factors for the "triangle" area of the VMesh, but luckily I had some interested and smart people around to bounce ideas off of.

Now that this is finished I'm getting really close to finishing the set of features I wanted to finish by the end of summer. I have a couple ideas for smaller features I could implement if I have enough time, mostly features people have asked for on DevTalk. (After bug fixes!)

  • Symmetry mode for the profile widget
  • Exporting and importing profiles from the widget to and from objects. I might delay this though to see how it could work with the upcoming asset manager project.
  • More adaptive profile sampling
  • Start thinking about boolean vertex meshes
  • Icons for profile presets
  • More advanced presets, functions that could build presets from inputs like the number of steps.

August 1

I continued working on smaller projects today. Here's a list of commits:

  1. Profile Widget: Dynamic Hi-Res table size
  2. Merge branch 'master' into soc-2019-bevel-profiles
  3. Profile Widget: Sometimes disable move / delete buttons
  4. Rest of rename from previous commit PROF_HANDLE_AUTO_ANIM to PROF_HANDLE_AUTO
  5. Profile Widget Curves: Further reduced complexity
  6. Bevel Custom Profile: Fixed sampling too many segments from widget.
  7. Bevel Cutoff Method: Don't use the cutoff method in the pipe case.

I also added a profile-widget-sampling RNA function, but I ran into some difficulty: The return array from the RNA function can't be of variable length because that functionality doesn't exist. The conclusion from there would probably be just to use the maximum size of the table, because you can't sample more points than that, but the RNA system only allows the return array to have a size of 32. I don't see much point in having a sampling function that's limited to 32 samples, so I think I'll disable this for now. If it's a requested feature later on I'll figure out how to solve this issue. But I'm not sure if I should leave the code there commented (it might be helpful in the future) or just delete it.

August 2

I started off today by trying to understand the process of interpolation from the greater power of 2 segment VMesh to the final. I'm pretty confident that it's a fine process to use for custom profiles-- it looks general enough and I don't see assumptions about non-custom superellipse profiles. It was marked on my backlog to try to understand it and document it with comments, but after looking through it for a bit I'm just not sure it's worth my time to do that right now. I have a feeble grasp of the basics of what it's doing and with enough time I think I could understand the whole thing, but I'm not the best person to document this code.

Anyway, that was a long way of saying I don't have to do anything there. I started looking at the harden normals code today, which is similarly pretty complicated and new looking, but I think I can get the hang of it, and helpfully I have some pretty specific goals in mind for this after talking to Howard.

August 5

Today and over the weekend I changed the sampling function to return a list of ProfilePoints rather than an array of floats. The primary objective here was to make it possible to carry over data about the sharpness of points from the control points to the sampled points and to be able to use that data for hardening the profiles of the bevel. But it also makes it possible to not use temporary arrays to transfer over the information to the new tables when they're created, and it provides for cleaner code in the bevel tool as well.

August 6

I looked over some miscellaneous bugs, although I didn't make much progress on most of them. At this point the remaining bugs are pretty tricky. I spent a while messing with the RNA system to try to add a better method to only sample new segment points from the widget when it's changed, but I ended up finding a pretty simple solution to that. I also finally talked to Campbell about whether the public widget functions should have a BKE_ prefix, and they should! He changed over the CurveMapping functions too!

I spent a while compiling the things I have left to do before starting the merging process. It's nice to have a public, organized list. It's really motivating too to check off an item from it! I would really like to get the short term stuff done as soon as possible so I can post a diff of the branch and hopefully start some code review. Although that might have to be after I get back from my trip at the end of August.

August 7

Today I spent a while working on the modifier and tool UI. It's fun to play around with the UI, and I like thinking about what would make it better. Once again I have to complain though that the functions in interface.c and interface_layout.c are not very well documented. It can be frustrating to spend a long time figuring out the difference between two functions with very similar names and no comments. There are also multiple ways to add items to the ui, which starts to get frustrating too-- the uiItem* functions, and the uiBut* functions (as well as the RNA_def* functions in other situations).

Anyway, I'm pretty happy with the UI and I shared a screenshot and some thoughts on DevTalk. There are a couple things that could be better which I mentioned there as well though. But I'm going to cross it off my list for now. And I fixed the high-res table not including the last control point of the profile too.

I also fixed the "fullness" calculation for the initial vertex mesh before subdivision, which again is very arbitrary in the custom profile case for the ADJ mesh, but it's better than it was before.

Tomorrow I want to fix the orientation bug-- it's getting pretty annoying. If I finish that I'd like to ask people on DevTalk for profile presets.

August 8

I've spent so much time working on the orientation bug today! There are two separate problems: One is that the orientation is being calculated incorrectly next to vertex meshes sometimes. This is probably an issue with the regularize_profile_orientation function. The other is that the profiles next to vertex meshes disobey the calculated profile just about every other time! And strangely this is usually the profiles on the vertical edges of a new cube. I'm guessing this is an issue with how the profiles are used. Another strange thing about this one is that using miters fixes the issue.

I've gone through a couple of possibilities for what could be causing the second problem (disobeying the calculated orientation):

  1. Incorrect reverse argument to calculate_profile: I know this is fixed because every call to this is either before the regularize profile orientation pass or is has !bndv->is_profile_start as the reverse parameter.
  2. get_profile_point with reversed segments: I looked through all the calls to this function and didn't find any with an ns - k argument for the ring segment where it didn't make sense, so I don't think this is the issue.

This leaves only a couple possibilities:

  1. The debug code to draw the profile orientation is incorrect.
  2. Some profiles aren't getting recalculated after the RPO pass. But I don't think I deleted any calls to calculate_profile so I'm not sure about that.
  3. The VMesh code doesn't care about the profile orientation. But I'm not sure why this would have changed.

Because this problem is really frustrating I took a break to spent some time this morning working on the UI. After some feedback on the forum I decided to use the same UI for the modifier and the tool. It's a big change but I'm used to it already, and I think it's an improvement.

August 9

After spending more time debuggint the profile orientation regularization code I ended up just rewriting it from scratch. Overall the process of fixing this has been so much more involved than I thought it would be. It's a very simple thing that needs to be done, but I guess there are enough details in the implementation that it can be hard to get right.

I wrote the new version as a recursive function that's called after the initial start function. That might make it a little less efficient, but I can make it a while loop later if I need to. I just want it to work!

After I finished writing it I debugged it for a while and found a bunch of stupid little changes. I used the graphical debugger in QT Creator for the first time which is definitely an improvement. But after spending the whole day on it I still had to finish up the say with it not working in even simple situations.

I think I'm really close to getting it work. I made a diagram and I have a clear idea of what needs to be done, and I think what remains is fixing some little details in the implementation that are throwing it off.

August 12

Hooray! After a lot of frustration and pain I finally fixed the profile orientation regularization problem! There were two key realizations that I had that made me realize the problem. The first is that setting each EdgeHalf's right boundvert's is_profile_start boolean is totally pointless and can cause a lot of errors! Because the profiles are defined in the counterclockwise direction, I should only set the property there!

I actually just forgot the second key realization. My brain is kind of fried after so much debugging. But it might have had to do with not setting the "second best angle" variable properly so it was returning a best edge even when it shouldn't.

I'm guessing the new version I wrote from scratch is probably slower, so I fixed the old version and made it used dot products instead of angles for a speed boost. Just for fun I'll try to profile it later just in case though.

August 13

I had a bit of a shorter day today as a break from thinking about profile orientations basically all of the time for the last five days. I did one of of the fun projects I'd been saving for a time like this and added the presets. On a family member and architect's suggestion I looked at a product catalog for moldings and added a couple of typical shapes from there. I didn't want to go crazy and add too many though because I want to open it up to suggestions from the community in case they have them. In general I think just a couple is enough too.

I also had a moment of inspiration and decided to take on a "Steps" preset. I didn't think I would get to this, but it looks really cool and it generates the right amount of control points based on the number of segments from the modifier or the tool.

One other thing: I started to write a script to get the number of "HANS-TODO" occurrences at the time of each commit throughout the summer. It would be fun to include a plot of this in my final report.

August 14

I worked in a lot of different areas today, a little bit in the UI, making the modifier and tool UI just a little more consistent, but mostly cleaning up around the bevel code. I tried fixing the cutoff method so it would work with the "Arc" outer miter, but I didn't get further than narrowing down why it doesn't work:

  • Miter profiles don't have plane_no filled, so the down direction is incorrect.
  • Indexing profile points of miters with (i, 0, k) seems to return zero except for the first and last profile point.

I'm pretty confident I can get around these two problems and make it work. It would really look a lot better if I did. But the other todo associated with the cutoff method is trickier. I need to figure out how to fill the face and vertex arrays that bev_create_ngon uses, and even the purpose of them. I may ask for help with this.

The biggest thing I finished today though is the documentation. It's really easy to set up, all I have to do is type "make." I'm not sure if this will need to go through review-- I already had someone look over it and I followed the guidelines-- but I'll just post the diff along with the patch when I post it and commit it to SVN when the patch lands. It was actually pretty fun writing the documentation and thinking about what someone would be wondering about when they use the custom profiles.

August 15

Today I updated the modal keymap for bevel to include the new features. A lot of keys are taken already but "Z" has a nice squiggly shape that looks a little like a custom profile, so I used that as a toggle for using the custom profile, which will be the same profile as was used in the tool last.

I also finally fixed the distribution of the extra samples. It was wrong before because it wasn't properly calculating the order of the edges based on their curvature, all of the indices in that array were just zero. So it was just going through and assigning all of the extra points to the first edge. To fix this I added a struct to store the index and curvature of edges, and a sorting function so that I could use qsort to get the curvature order. This should be faster too, although not by much.

I also looked into why some of the information I'm counting from the Profile struct in the cutoff VMesh method isn't there for miter profiles. I don't have a solution for this yet but I'd like to.

August 17

Today I wanted to prepare my laptop to be able to use it on my trip, which launched into a huge adventure / torture of getting make deps to work so I could build Blender properly. I basically spent all day on it along with some packing and working on some cleanup and even length sampling, but even at the end I was having the same issue I had at the beginning of the way. The problem is during the linking process of OpenImageIO, where it thinks I have a different version of webP libraries than I actually do (or something like that). But there's also an issue with the make deps step itself where I have to give it root permissions even though it should only be writing to Blender's libs folder.

Although they shouldn't be, these problems might be related to the distrobution I'm using, Manjaro, which tends to produce more errors in situations like this I gather. So if I need to I will install Ubuntu 19.04. Or I might just have time to work on my final report on my trip.