SODB(3iv)

πŸ’– SoDB(3IV) πŸ’–

okay bestie, sit down, hydrate, and let's talk about SoDB β€” the scene graph database class, from the 3IV manual, part 1 of 2, so don't you dare close the tab 🫢


✨ NAME ✨

SoDB β€” scene graph database class, and yes she's the moment πŸ’…


🌸 INHERITS FROM 🌸

SoDB</purl>


πŸŽ€ SYNOPSIS πŸŽ€

#include <Inventor/SoDB.h>

typedef void        SoDBHeaderCB(void *userData, SoInput *in)

Methods from class SoDB:

static void            init()
static const char *    getVersion()
static SbBool          read(SoInput *in, SoNode *&rootNode)
static SbBool          read(SoInput *in, SoPath *&path)
static SoSeparator *   readAll(SoInput *in)
static SbBool          isValidHeader(const char *testString)
static SbBool          registerHeader(const SbString &headerString, SbBool
                            isBinary, float ivVersion, SoDBHeaderCB
                            *preCB, SoDBHeaderCB *postCB, void *userData)
static SbBool          getHeaderData(const SbString &headerString, SbBool
                            &isBinary, float &ivVersion, SoDBHeaderCB
                            *&preCB, SoDBHeaderCB *&postCB, void
                            *&userData, SbBool substringOK = FALSE)
static int             getNumHeaders()
static SbString        getHeaderString(int i)
static SoField *       createGlobalField(const SbName &name, SoType type)
static SoField *       getGlobalField(const SbName &name)
static void            renameGlobalField(const SbName &oldName, const
                            SbName &newName)
static void            setRealTimeInterval(const SbTime &deltaT)
static const SbTime &  getRealTimeInterval()
static void            setDelaySensorTimeout(const SbTime &t)
static const SbTime &  getDelaySensorTimeout()
static int             doSelect(int nfds, fd_set *readfds, fd_set
                            *writefds, fd_set *exceptfds, struct timeval
                            *userTimeOut)

🌈 DESCRIPTION 🌈

so SoDB is THE class that holds all the scene graphs. every single one. each one is a 3D scene that your app is out here using, living its main character life ✨

a scene graph is literally just a collection of SoNode objects, and those come in several varieties (peep SoNode for the tea on that) πŸ¦‹

🚨 okay this part is non-negotiable bestie: your app programs must initialize the database by calling SoDB::init() before calling any other database routines, and before constructing any nodes, paths, functions, or actions. no skipping. no "I'll do it later". periodt. πŸ’…

and here's the cute lil shortcut: SoDB::init() gets called by SoInteraction::init(), SoNodeKit::init(), and SoXt::init() β€” so if you're already calling any of those methods, you do not need to call SoDB::init() directly. she's already handled it for you, we love a delegation queen πŸ‘‘

also every single method on this class is static. all of them. no cap.


πŸ“ typical program database initialization and scene reading πŸ“

it goes a lil something like this:

#include <Inventor/SoDB.h>
#include <Inventor/SoInput.h>
#include <Inventor/nodes/SoSeparator.h>

SoSeparator  *rootSep;
SoInput      in;

SoDB::init();
rootSep = SoDB::readAll(&in);
if (rootSep == NULL)
    printf("Error on read...\n");
 ...

and if rootSep comes back as NULL? yeah bestie that's an error on read, the printf is telling you, it's giving sad girl era 😭


okay that's part 1, more is coming so stay tuned πŸ’–

✨ METHODS ✨

Okay bestie, this is where the actual magic happens. Buckle up. 🎒

🌱 static void init()

static void init()

This initializes the database, and no cap, you must call this before you call literally any other database routine. That includes constructing any nodes, paths, engines, or actions. It's giving "first step or nothing works," periodt. πŸ’…

🏷️ static const char * getVersion()

static const char *    getVersion()

Returns a character string that tells you which version of the Inventor library is in use. Slay. ✨

πŸ“– static SbBool read(...)

static SbBool          read(SoInput *in, SoNode *&rootNode)
static SbBool          read(SoInput *in, SoPath *&path)

Reads a graph from the file specified by the given SoInput. It returns a pointer to the resulting root node in rootNode, or a pointer to the resulting path in path. The programmer is responsible for figuring out which routine to use, based on what's in the input. These routines return FALSE if any error happened during reading. 😭

If the passed SoInput was used to open a file and the name of that file contains a directory, SoDB automatically adds the directory to the end of the current directory search path in the SoInput. That means nested files named in SoFile nodes may be found relative to that directory. The directory is removed from the search path when reading is complete. So tidy. ✨

πŸ—‚οΈ static SoSeparator * readAll(SoInput *in)

static SoSeparator *   readAll(SoInput *in)

Reads all graphs and paths from the file specified by the given SoInput. If there's only one graph in the file and its root is an SoSeparator, a pointer to the root is returned. In all other cases, this creates an SoSeparator, adds the root nodes of all graphs read as children of it, and returns a pointer to it. This returns NULL on error. It processes directory paths in the same way as the other reading routines. Cute and consistent. πŸŽ€

βœ… static SbBool isValidHeader(const char *testString)

static SbBool          isValidHeader(const char *testString)

This returns TRUE if the given character string is one of the valid Inventor file headers, (e.g. "#Inventor V2.0 binary"), or if the string has been registered as a valid header through the registerHeader method. Vibe check passed. πŸ’–

πŸ“ static SbBool registerHeader(...)

static SbBool          registerHeader(const SbString &headerString, SbBool
                             isBinary, float ivVersion, SoDBHeaderCB
                             *preCB, SoDBHeaderCB *postCB, void *userData)

Registers the given string as a valid header for input files. The string must be 80 characters or less, and start with the comment character '#'. If the passed isBinary flag is true, any file with this header will be read as a binary file. Usually, a user-defined header represents a file format that is a superset of the Inventor file format. The ivVersion number indicates which Inventor file version this header corresponds to. The user-defined callback functions preCB and postCB are called before and after a file with this header is read. The userData is passed to both callback functions. The method returns TRUE if the header is successfully registered. Note, nothing prevents you from registering the same string multiple times. Go off, register it twice. πŸ™ˆ

πŸ” static SbBool getHeaderData(...)

static SbBool          getHeaderData(const SbString &headerString, SbBool
                             &isBinary, float &ivVersion, SoDBHeaderCB
                             *&preCB, SoDBHeaderCB *&postCB, void
                             *&userData, SbBool substringOK = FALSE)

Passes back the data registered with the given header string, including the flag specifying whether the string is for a binary file, pointers to the callback functions invoked before and after reading the file, and a pointer to the user data passed to the callback functions. If the given header string does not match any of the registered headers, and the substringOK flag is TRUE, then the method will search for a registered header that is a substring of the given string. The method returns TRUE if a matching registered header, or subheader, was found. Default substringOK is FALSE, bestie. πŸ’…

πŸ”’ static int getNumHeaders()

static int             getNumHeaders()

Returns the number of valid headers, including standard Inventor headers, and user-registered headers. Count 'em up. πŸ”₯

🏷️ static SbString getHeaderString(int i)

static SbString        getHeaderString(int i)

Returns the i'th header. Simple as that. ✨

🌍 static SoField * createGlobalField(const SbName &name, SoType type)

static SoField *       createGlobalField(const SbName &name, SoType type)

The database maintains a namespace for global fields, making sure that there is at most one instance of a global field with any given name in the database. This routine is used to create new global fields. If there is no global field with the given name, it will create a new global field with the given name and type. If there is already a global field with the given name and type, it will return it. If there is already a global field with the given name but a different type, this returns NULL. So don't try to mix types, okay? 😭

All global fields must be derived from SoField; typically the result of this routine is cast into the appropriate type; for example:

     SoSFInt32 *longField =
         (SoSFInt32 *) SoDB::createGlobalField("Frame",
                                              SoSFInt32::getClassTypeId());

Iconic casting moment. πŸ’…

πŸ”Ž static SoField * getGlobalField(const SbName &name)

static SoField *       getGlobalField(const SbName &name)

Returns the global field with the given name, or NULL if there is none. The type of the field may be checked using the SoField::isOfType(), SoField::getClassTypeId(), and SoField::getTypeId() methods. Use those to peek at the vibe. πŸ‘‘

✏️ static void renameGlobalField(const SbName &oldName, const SbName &newName)

static void            renameGlobalField(const SbName &oldName, const
                             SbName &newName)

Renames the global field named oldName. Renaming a global field to an empty name ("") deletes it. If there is already a global field with the new name, that field will be deleted (the getGlobalField method can be used to guard against this). So maybe check first, bestie. πŸ™ˆ

⏰ static void setRealTimeInterval(const SbTime &deltaT)

static void            setRealTimeInterval(const SbTime &deltaT)

The database automatically creates one global field when SoDB::init() is called. The realTime global field, which is of type SoSFTime, can be connected to engines and nodes for real-time animation. The database will automatically update the realTime global field 12 times per second, using a timer sensor. Typically, there will be a node sensor on the root of the scene graph which schedules a redraw whenever the scene graph changes; by updating the realTime global field periodically, scene graphs that are connected to realTime (and are therefore animating) will be redrawn. The rate at which the database updates realTime can be controlled with this routine. Passing in a zero time will disable automatic update of realTime. If there are no enabled connections from the realTime field to any other field, the sensor is automatically disabled. πŸ›‘

Note that the SoSceneManager class automatically updates realTime immediately after redrawing, which will result in as high a frame rate as possible if the scene is continuously animating. The SoDB::setRealTimeInterval method ensures that engines that do not continuously animate (such as SoTimeCounter) will eventually be scheduled. Okay, that's the tea. 🍡

⏱️ static const SbTime & getRealTimeInterval()

static const SbTime &  getRealTimeInterval()

Returns how often the database is updating realTime. Clock check. ⏰

⏳ static void setDelaySensorTimeout(const SbTime &t)

static void            setDelaySensorTimeout(const SbTime &t)

This sets the timeout value for sensors that are delay queue sensors (one-shot sensors, data sensors). Delay queue sensors are triggered whenever there is idle time. If a long period of time elapses without any idle time (as when there are continuous events to process), these sensors may not be triggered. Setting this timeout value ensures that if the specified length of time elapses without any idle time, the delay queue sensors will be processed anyway. So they don't just ghost you. πŸ’€

βŒ› static const SbTime & getDelaySensorTimeout()

static const SbTime &  getDelaySensorTimeout()

Returns the current delay queue timeout value. That's it, that's the method. ✨

πŸŽ›οΈ static int doSelect(...)

static int             doSelect(int nfds, fd_set *readfds, fd_set
                             *writefds, fd_set *exceptfds, struct timeval
                             *userTimeOut)

In order to keep timer and idle sensors running as expected, it is necessary that an Inventor application not block waiting for input. If the Inventor application uses the Xt utility library, this can be handled automatically. However, if the application is using its own event loop, this function is provided as a wrapper around select(2) that will handle Inventor tasks if necessary instead of blocking. So don't just sit there waiting, bestie. Go handle your tasks. 🫢


πŸ”— SEE ALSO πŸ”—

  • SoBase
  • SoNode
  • SoEngine
  • SoField
  • SoInput
  • SoFile
  • SoPath
  • SoOneShotSensor
  • SoDataSensor
  • SoXt

That's the whole manual page, bestie. Source/version: SoDB(3IV)(). Stay slay, and may your sensors always fire. πŸ’–βœ¨πŸ‘‘