C++ observer?

I have a c++ exporter that is working well. Now I would like to be able to update (or freshen) my export anytime the Sketchup model is changed (add/remove/modify types of actions).

Is there a way to do this in C++, and if not, is there a right way to do it in Ruby, and have it trigger actions in my c++ code?

This is going to be an issue for users. They already complain when autosave kicks in on it’s set interval.
I cannot see users being fond of having your exporter kick in after every change. But this is just my opinion.

There no longer is a SketchUp C++ API. All vestiges of the old one was removed (I think for the initial 2019 release.) Only the C++ importer and exporter interfaces remain, AFAIK.

Yes. Ruby itself is implemented in C. You can get a reference to the open model and create Ruby observer objects on the C side, by making Ruby C calls. (Also for SU2019.2+ there is a C function exported by the application in “application.h” of the C API, … meant currently for read only use. It provides access to the “live” active model reference.)

Thomas has created a project for a SketchUp Ruby C extension at GitHub.

You’ll need the same Ruby version header files for the SketchUp version your exporter targets.
SketchUp version 2021 uses Ruby 2.7.1, (SU2019 and SU2020 use Ruby v2.5.5, SU2017 & 2018 use Ruby v2.2.4; SU2015 & SU2016 use Ruby v2.0.0.)

If you download the C SDK it may contain other examples. It also has the Ruby Core C header files for the current SketchUp version(s) which are 2019.2 and 2020.0.1, (ie Ruby ver 2.5.5-p157.)


Also I’ve posted a link to a free PDF book on writing Ruby C extensions which can help you a lot. It has a glossary of the most used Ruby Core C functions. It’s link is at the bottom of the Books section …


There are quite a few topic threads on accessing “live” models via C here, probably in the C SDK subcategory, but perhaps in the Ruby API subcategory. If you search from this (parent) category the results will be from all 3 categories.


:bulb:

That helped. As an associated question, I am calling SUModelGetEntities to get the entities to export, but it seems to only get the entities that were present at the last save. Is there a way to get the current entities?
Edit: looks like I need to use SUApplicationGetActiveModel, but when I replace

SU_CALL(SUModelCreateFromFile(&model_, src_file.c_str()));
with
SU_CALL(SUApplicationGetActiveModel(&model_));

in my c++ code, I get “identifier “SUApplicationGetActiveModel” is undefined”

I have searched my SDK download, but have not found it there

Of course the former is designed to load a SKP file into a SUModelRef object.

(1) There is a linking difference in using the C API for files and the live application.
Did you link to the correct libraries ?

I think for working in standalone mode on files (a 3rd party app or command line utility) you link to the DLLs, but if working within the live application, you link to the LIBs. Both are in "binaries\sketchup\x64" folder of the SDK.

(2) SUApplicationGetActiveModel is only exported from versions 2019.2 and later, so you also need 2019.2 or later. IF you have (or are targetting) earlier versions then there is an undocumented Ruby trick to get the live model reference.

As said above, it is defined in "headers/.../application/application.h" and it (and anything to be added to this file in the future) is only exported by the SketchUp application and via the “live” library.

Apparently I had an older SDK. I downloaded a fresh copy, and it now compiles, thank you!

1 Like

Great! I would suggest however that perhaps you leverage one of the live Ruby Sketchup::ModelObserver onSave callbacks rather than try to attach observer(s) to a multitude of geometry objects.

Now that you have a valid reference to the live model object, you have an object to attach an observer object to.

1 Like

Update: it compiles, but when it runs it throws an “unknown exception” error.
try
{
SUModelRef liveModel_;
SUSetInvalid(liveModel_);
SU_CALL(SUApplicationGetActiveModel(&liveModel_));
}
catch (const std::exception& e)
{
std::string foo = e.what();
}
I am linking both the sketchup.lib and SketchUpAPI.lib and I am running SketchUp Pro version 19.3.253.

FYI, a wiki I wrote on how to post lexed code in the forum …

Did you initialize the API ?

Further reading …
https://forums.sketchup.com/search?q=SUApplicationGetActiveModel%20category%3A12

My exporter code is an expansion of the Quick Start “reading from a .skp file” code, and it works well. I have swapped the line

SUResult res = SUModelCreateFromFile(&model, "model.skp");

for

SUResult res = SUApplicationGetActiveModel(&model);

and when I run it, res = SU_ERROR_NO_DATA, and model = {ptr=0x0000000000000000 }

At what point in the load cycle are you getting a 0 pointer ?

Ie, after the extensions load, SketchUp goes through any attached AppObservers and polls them for an expectsStartupModelNotifications() callback that returns true and if so, then checks if they have either an onNewModel or onOpenModel callback and calls the appropriate one.

(If I remember correctly,) the point in time when the model reference is valid differs per platform (WIN vs MAC,) but on both at this time (when observers are polled as explained above) extensions can rely on the model having been loaded and/or initialized when their extension’s AppObserver callbacks get called.

I often have a pattern where both the new and open model callbacks call the same internal init method in an extension submodule.

Anyway … this pattern is the functional opposite of your previous topic on knowing when SketchUp is closing …

My onQuit observer is working fine, thank you for your help with that. At this point I am just trying to get live model export to work. My plugin has a toolbar button that calls the export process (based on the Quick Start code sample). It works with SUModelCreateFromFile(&model, “filename.skp”), but not with SUApplicationGetActiveModel(&model). I do have a model loaded. I realize I have strayed from the original observer question, should I start a new question?

No keep this all together till it’s solved.

I’ve pinged Thomas to see if he has an idea.

All I can think of is that the API libs and your running version of SketchUp need to be 2019.2 or higher.

I am running SketchUp Pro version 19.3.253.
The files in my SketchUp API have dates of 1/17/2020

I’m late to the party here, but were you able to get things working?

1 Like