Skip to content

Conversation

@neofelis2X
Copy link
Collaborator

Hi,

it is long overdue that I push this work on the 3D view. It reorganises / moves / rewrites most of the code that handles the opengl canvas. It does not enable pyglet 2, everything is still based on pyglet 1.5. But it makes all the foundational changes necessary to use modern OpenGL (3.3+).

That incldues:

  • All opengl calls are now inside the gl package
    • they were all over the place and very hard to work with before
  • Move duplicated code to canvas class and reuse it
    • stlview and gcodeview are not that different after all
  • New camera class based on vectors
    • no more dolly-zoom by scaling the whole scene...
  • Keyboard shortcuts organised in keyboard input class
  • Fix various bugs on macOS / highDPI displays / mouse cursor
  • Implement optional frametime counter
  • Define all 3D objects as actors (gl/actors)
  • Draw the gridlines starting from center
  • Add indicator to grid which indicates the origin point (0, 0)
  • Gcode plater and Stl plater inherit background color from settings
  • Grid and focus outline change color based on background
  • Add 3D testfiles in different formats
  • Prepare some to code for vertexbuffers and shaders

I know this are a lot of changes and all in one PR. It has taken me a while to untangle it all and I have changed bit by bit, going through it all. In my opinion this was necessary to get a more modern starting point to work with. Splitting it into smaller PRs would be a hindrance. On the other hand, the following PR for pyglet 2 should be more concise.

Note 1: When the diff says that there are 50.000 new lines of code then that is because I added a .gcode testfile.
Note 2: I already have a branch where everything runs on pyglet 2 and it's working really well. But still work in progress.

Fixes #746
Fixes #1035
Fixes #1301

I would be happy if you can test it on your respective operating system. On macOS it runs really well and I also tested it on windows and it looked good. Any input is welcome!

neofelis2X and others added 30 commits April 8, 2025 23:07
@neofelis2X
Copy link
Collaborator Author

Hello @DivingDuck

Sorry for my late answer, it was a busy week for me.

No worries, there is no rush! Your additional information helped me to pin down the problems a bit further.

Mouse scroll wheel for zooming is still not working. Last time I forgot to mention that pan and tilt are working as it is for this version

I was able to reproduce this when I scale down the 3d view to a very small window. I believe zoom not working was caused by a minimum and maximum zoom distance, that I added to the code. I turned this off and hope this will solve this issue.

For the plater window (stl plater) it still have a problem with handling the stl file in opengl and the fall back in 2D view.

After looking into this I found out that I didn't set the current context before loading a new 3d model. I hope this is fixed now.

I saw the color of the grid have changed from green to something grayish and recognize that I can't change the color of the grid anymore. It looks like we lost the color setup for this since quite some time (what I thought we had before if I remember correct).

Yes, the grid had a hard coded colour before. I now changed it in a way that it automatically becomes light grey or dark grey, depending on the colour of the background. Implementing a user picked colour can also be done, if we want that.

Fit model in window position is not correct (this behavior exists already before)

Yes it is not very good, but it should behave the same way a before. Implementing a better algorithm was not on my todo list for this PR. Too many small details.

So, feel free to test the new binaries, when you find the time. I am optimistic that this two points have been fixed now.

@DivingDuck
Copy link
Collaborator

DivingDuck commented Jun 1, 2025

Hi @neofelis2X,
thanks for the updates. Very nice. Good news, most of my findings are solved. Yay.

I was able to reproduce this when I scale down the 3d view to a very small window. I believe zoom not working was caused by a minimum and maximum zoom distance, that I added to the code. I turned this off and hope this will solve this issue.

Solved.

After looking into this I found out that I didn't set the current context before loading a new 3d model. I hope this is fixed now.

Yes. Solved too.

Yes, the grid had a hard coded colour before. I now changed it in a way that it automatically becomes light grey or dark grey, depending on the colour of the background. Implementing a user picked colour can also be done, if we want that.

This seems not to work. On my computer I can't see the grid anymore. Maybe the color is there but I can't see it.
Solved.
#1498Grid
I think we should try using the color from the setting options color menu so that all plate colors looking equal and we have a single point for managing those values. Same for all plate dimensions, we should use there as well the values from the settings.

Saying this, I recognize again that we should rework the whole setting story. Is it only me who is stumbling all the time in finding out where a specific default or fix setting was made in our code? I think we should have a central place for those values. Maybe worth or a future project.

Question, is it possible to draw an outer line around the print bed so that one can see what print bed is actual in use (only if it is not a huge effort to do)?
Background: I have different print beds. Some are rectangular, some are square and one printer have two independent print beds where I can combine the beds into one big or into independent print areas where I use both or only one of them. Seeing the actual bed frame visual can help preserve me making stupid mistakes (don't ask how do I know).

Edit: no longer needed as the grid solved this too.

Yes it is not very good, but it should behave the same way a before. Implementing a better algorithm was not on my todo list for this PR. Too many small details.

Don't worry, this is somehow as well much better than in my last test. It looks like the zoom problem had forced this glitch.

Edit: You fixed the grid issue already. 👍

@DivingDuck
Copy link
Collaborator

DivingDuck commented Jun 1, 2025

Hi @neofelis2X,
I got an other error:

Traceback (most recent call last):
  File "C:\Users\Armin\Source\Repos\DivingDuck\Printrun\v3\Lib\site-packages\wx\core.py", line 3425, in <lambda>
    lambda event: event.callable(*event.args, **event.kw) )
                  ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: wrapped C/C++ object of type TempGauge has been deleted
Traceback (most recent call last):
  File "C:\Users\Armin\Source\Repos\DivingDuck\Printrun\v3\Lib\site-packages\wx\core.py", line 3425, in <lambda>
    lambda event: event.callable(*event.args, **event.kw) )
                  ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: wrapped C/C++ object of type TempGauge has been deleted
Traceback (most recent call last):
  File "C:\Users\Armin\Source\Repos\DivingDuck\Printrun\v3\Lib\site-packages\wx\core.py", line 3425, in <lambda>
    lambda event: event.callable(*event.args, **event.kw) )
                  ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Armin\Source\Repos\DivingDuck\Printrun\printrun\gui\graph.py", line 390, in StartPlotting
    self.Refresh()
    ~~~~~~~~~~~~^^
RuntimeError: wrapped C/C++ object of type Graph has been deleted
Traceback (most recent call last):
  File "C:\Users\Armin\Source\Repos\DivingDuck\Printrun\v3\Lib\site-packages\wx\core.py", line 2338, in Notify
    self.notify()
    ~~~~~~~~~~~^^
  File "C:\Users\Armin\Source\Repos\DivingDuck\Printrun\v3\Lib\site-packages\wx\core.py", line 3550, in Notify
    self.result = self.callable(*self.args, **self.kwargs)
                  ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Armin\Source\Repos\DivingDuck\Printrun\printrun\gl\panel.py", line 182, in Refresh
    return super().Refresh(eraseback)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^
RuntimeError: wrapped C/C++ object of type GcodeViewPanel has been deleted

The way I force this: Open Pronterface, go to -->Settings -->Options -->Viewer and then for [3D viewer options] check / uncheck both settings for [Use a lighter 3D visualisation] and [Use perspective view instead of orthographic] and then hit the Ok button.
Sometimes this happen only when you restart Pronterface.

#14983DViewerOptions

Edit:
I just check this on our latest release and we also have a problem doing this if both entries change at the same time

@neofelis2X
Copy link
Collaborator Author

Hi @DivingDuck, so I made some changes to avoid that error.

Edit: You fixed the grid issue already.

Great, I am glad that this is fine now. I messed up the colour calculation, but fixed it shortly afterwards.

I will see if I can add the grid colour to the settings.

Saying this, I recognize again that we should rework the whole setting story. Is it only me who is stumbling all the time in finding out where a specific default or fix setting was made in our code? I think we should have a central place for those values. Maybe worth or a future project.

I just check this on our latest release and we also have a problem doing this if both entries change at the same time.

Yes, I absolutely agree. The settings are confusing and I try to avoid messing with them, when I can.

This specific error you mentioned can be triggered in many different ways, especially when multiple settings are changed at the same time. The way Pronterface applies changed settings is brute force, it sometimes calls reload_ui multiple times in a row.

To improve this a little bit I changed 2 things:

  1. Panels and widgets are now destroyed with DestroyLater which gives them times to wait for pending events.
  2. reload_ui now waits for at least 1 ms, to catch any following calls to reload_ui. This is not noticeable to the user, but seems to work well.

As you say, generally the whole settings system should probably be reworked. I never quite understood the flow of actions when changing a setting.



if __name__ == '__main__':
pass
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this line necessary? Are we ever running this file as a standalone?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, especially in this file it is actually not necessary.

# BASE_CLASS = wx.Window
# Subclassing Panel solves problem In Windows
BASE_CLASS = wx.Panel
# BASE_CLASS = wx.Panel
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgive my ignorance here, if the focus issue is solved for all operating systems, could we remove this line instead of commenting it out? In fact could we remove the other comments and just leave a comment on why we subclass GLCanvas?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the comments in the pyglet2 branch. I leave them in here for now, in case anything comes up. Can't really test linux systems that much.

self.pygletcontext.canvas = self
self.pygletcontext.set_current()
# Uncomment this line to see information about the created context
# print(f"OpenGL context version: {self.pygletcontext.get_info().get_version()},\n",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe put this on a logging.debug call? Or would it mean too much clutter?

self.focus.update_size()
self.OnInitGL(call_reshape = False)
# print('glViewport', width)
# print('glViewport: ', width, height)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this print comment? Use a logging.debug kind of message instead?

# glCallList(self.display_list)
self.draw()

'''
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these apostrophes for?

Copy link
Collaborator Author

@neofelis2X neofelis2X Jun 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about it... I will just leave a TODO and delete the rest of the old code.

normals.extend(facet[0])

"""
if hasattr(model, 'indices') and model.indices:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you leaving this bit of code commented out for a future use?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was inteded for future use, but the future turned out to be a pure OpenGl approach. I will clean it up.

if answer == wx.OK:
self.DestroyLater()
return
# This works but no features are implemented
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove these comments? I think the message works fine no need to load an empty window.

@rockstorm101
Copy link
Collaborator

Hi @neofelis2X,

I've played around a bit and found no show-stoppers. Great job!

As you say, generally the whole settings system should probably be reworked. I never quite understood the flow of actions when changing a setting.

I agree, it is something I've looked at before. But refactoring the settings system to use something less "homemade" like maybe ConfigParser, wasn't simple. Particularly regarding macros. I could not achieve a solution that wasn't a breaking change for users and/or required a lot of code and effort to keep backwards compatibility.

@DivingDuck
Copy link
Collaborator

DivingDuck commented Jun 11, 2025

Hi @neofelis2X,
I test your last update today: This is solved now. Yay and again great job!

... and I found two other (sorry):

  • When -->Settings -->Options -->Viewer and then for [3D viewer options] is enabled:
    Reset view [R] is working fine but Fit [F] is only shifting to the right and not zooming to the model for gcode view window/main visualization window and fit to the plate size for stl- and gcode-plater (looks the same like I do reset view)
    I recognize this behavior now the first time as I usually don't have this option enabled. By checking our last releases I see this behavior as well.

  • I run plater.py as stand alone version and recognize that there is a problem in loading stl files. You can import one first file but when you try to open a second file the app will go in an infinite loop.

Edit 2025-06-13:
I somehow lost to mention: [Use perspective view instead of orthographic] need to be activated for forcing the error

@neofelis2X
Copy link
Collaborator Author

neofelis2X commented Jun 14, 2025

Hi @rockstorm101, good to hear and thank you very much. I saw only right now that you added some comments, i will look into them.

I could not achieve a solution that wasn't a breaking change for users and/or required a lot of code and effort to keep backwards compatibility.

Ye I have no doubt that this would be difficult to achieve. Luckily there is no urgent need to change anything.

Hello @DivingDuck, thanks I see we are making progress and even some older bugs get fixed. I think it's good to improve as much as possible, when it can be included easily in this PR. :)

Regarding the [Fit to Frame] shortcut... For the platers it is not implemented. The Stl models do not even have bounding boxes yet, that's why platers just call [Reset view]. The problem with in the main view has probably todo with too big bounding boxes. i will test an example.

I run plater.py as stand alone version and recognise that there is a problem in loading stl files. You can import one first file but when you try to open a second file the app will go in an infinite loop.

Hmm that is strange, seems to happen only on windows. In my pyglet2 branch it does not have any issues with loading. That could be a hint. Otherwise i'm at a loss here for now.

@neofelis2X
Copy link
Collaborator Author

I somehow lost to mention: [Use perspective view instead of orthographic] need to be activated for forcing the error

Sorry, which Error? The plater never use perspective view, because this settings is not given to them. Do you mean the [Fit] Error?

@neofelis2X neofelis2X self-assigned this Jun 14, 2025
@DivingDuck
Copy link
Collaborator

DivingDuck commented Jun 15, 2025

Hi @neofelis2X,
Indeed, with modernizing/rework the code you fix some of the old errors on the fly :)

For the Fit / Reset view problem:
Here is how I force the error on my system. Open a gcode file, hit Fit[F] and Reset[R]. Then change the setting of -->Settings -->Options -->Viewer and then toggle for [3D viewer options] the setting of [Use perspective view instead of orthographic] and save the change with [OK]. Hit Fit[F] and Reset[R] again. Now you can see the different behavior between perspective and orthographic view.

PrintrunOrtjogaphic1

Shame on me regarding the stl and gcode plater issue, I looks like got confused during my tests. I can't reproduce it. You are right

A little fun thing, this week I was searching in the math lib a function and remember a change you did in actors.py regarding 2*pi when I saw math.tau. You can use the constant math.tau instead of 2*math.pi and save the need for a multiplication in line 361, 735, 737 and 956. Maybe worth a little runtime code optimization in remember of the tau day 2025 in June 😇

Regarding the plater.py as stand alone app, it looks like something went wrong and crash or loop (? ) the app when it try to open the add model dialog a second time. Interestingly when I run it in visual studio in debug mode it sometimes is successful and sometimes not. In running from code w/o debugging it all times crash when I try to load a second stl file. It looks like there is a timing problem. I also try to run plater as binary file and it sometimes run and more often it hangs after I click the button Add Model for a additional stl file.

@DivingDuck
Copy link
Collaborator

We have a Fit to screen for the plater yay!
I'm just testing the gcode plater and found maybe the answer why you get sometimes trouble to make fit to screen working better in the past. There seems to be a "problem" in identification where a model starts and the travel of the nozzle to the first layer point.

It looks like there is a need for eliminating the first travel when we import a gcode model. This maybe causes some headache because of how do I identify what is the real model position and what is add-on code like travel or a purge line and so on.

In the end this is where users responsibility come in place as I don't see a way how this can be solved automatically. The only "help" I can think of is giving the user the possibility of editing the gcode like we do this in the gcode view.

@neofelis2X
Copy link
Collaborator Author

We have a Fit to screen for the plater yay!

Yes, I went in and added this functionality. It turned out to be much easier than I expected and I'm honestly very happy with the result.

There seems to be a "problem" in identification where a model starts and the travel of the nozzle to the first layer point.

Exactly, thats also what I found. Some Slicer configs add some extra extrusions to prime the nozzle and whatnot. The gcoder calculates the bounding box (minimum and maximum extensions) based on all extrusion moves. The only idea I have here is to not include the first layer into the bounding box. But that doesnt seem clean and is probably complicated. I'm better not touching the gcoder.

I will implement a visible bounding box into the pyglet2 branch, maybe that is helpful.

You can use the constant math.tau instead of 2*math.pi and save the need for a multiplication in line 361, 735, 737 and 956.

Cool! I was not aware that tau is a thing in python. I will add it.

@neofelis2X
Copy link
Collaborator Author

neofelis2X commented Jun 17, 2025

I also had some time on windows to test the failing FileDialog.

Interestingly when I run it in visual studio in debug mode it sometimes is successful and sometimes not. In running from code w/o debugging it all times crash when I try to load a second stl file.

Yes I tried it with Microsofts Python debugger and while stepping through it, it does not happen. When running normally, it hangs on the second time opening the dialog.

  • it hangs for plater.py and gcodeplater.py, but only in standalone mode.
  • it works fine when the platers are opened from within Pronterface.
  • the python code should be correct. I tried some variations and minimal implementations and it always hangs.
  • it also hangs in the current main branch, so it's not related to the changes in this PR.
  • Windows protocols call the hang a Cross-thread error

Maybe it has something to do with multithreaded COM calls. I found this wxWidgets issue on that topic: wxWidgets/wxWidgets#23578

My only idea here: Replace this native FileDialog with a non-native variant that wxPython offers? I would have to try that.

@DivingDuck
Copy link
Collaborator

Hi @rockstorm101 , @neofelis2X ,

Sorry that I had no time the last months.

I think we should release this PR. I haven't a solution for the standalone jet but I guess that most of the users didn't use the standalone version of Plater - at least for Windows and macOS we do not publish a executable binary. We can open an issue to keep that problem in mind for future improvements.
What do you think?
Best regards, DD

PS: Thanks for implementing TAU :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants