SoLOD(3)

πŸ“¦ version 3.1.3, in fedora 43, fedora 44

πŸ’– SoLOD πŸ’–

okay bestie, welcome to the SoLOD(3) page β€” yes it's from the Library Functions Manual and yes it's a whole vibe. grab a snack, this one's long 🌸


✨ NAME ✨

SoLOD β€” the SoLOD class is used to choose a child based on the distance between the viewer and the object. like, it literally picks which of its kids gets to show up depending on how far away you're standing. main character energy, honestly πŸ‘‘


πŸ¦‹ SYNOPSIS πŸ¦‹

#include <Inventor/nodes/SoLOD.h>

Inherits SoGroup. so it's a group node, it's got children, it's got ✨opinions✨ about which child you actually see.


πŸŽ€ Public Member Functions πŸŽ€

  • virtual SoType getTypeId (void) const β€” hands you back the runtime type id, the little name tag that says "yep, that's me" πŸ’…
  • SoLOD (void) β€” the constructor. no children yet, just vibes.
  • SoLOD (int numchildren) β€” the constructor but you tell it up front how many children it's gonna have.
  • virtual void doAction (SoAction *action) β€” the big action dispatcher, runs the action over this node.
  • virtual void callback (SoCallbackAction *action) β€” the SoCallbackAction flavored entry point.
  • virtual void GLRender (SoGLRenderAction *action) β€” the SoGLRenderAction flavored entry point, aka draw time.
  • virtual void GLRenderBelowPath (SoGLRenderAction *action) β€” render action, but for when we're below the path.
  • virtual void GLRenderInPath (SoGLRenderAction *action) β€” render action, but for when we're in the path.
  • virtual void GLRenderOffPath (SoGLRenderAction *action) β€” render action, but for when we're off the path. it's giving "not on the list" 😭
  • virtual void rayPick (SoRayPickAction *action) β€” the SoRayPickAction flavored entry point.
  • virtual void getBoundingBox (SoGetBoundingBoxAction *action) β€” the SoGetBoundingBoxAction flavored entry point.
  • virtual void getPrimitiveCount (SoGetPrimitiveCountAction *action) β€” the SoGetPrimitiveCountAction flavored entry point.
  • virtual void audioRender (SoAudioRenderAction *action) β€” the SoAudioRenderAction flavored entry point. sound girlies rise 🎧
  • virtual void notify (SoNotList *nl) β€” the notification hook, tells the world something changed.

πŸ’œ Public Member Functions inherited from SoGroup πŸ’œ

  • SoGroup (void) β€” constructor, empty group.
  • SoGroup (int nchildren) β€” constructor with a headcount for the children.
  • virtual void addChild (SoNode *node) β€” add a child to the end.
  • virtual void insertChild (SoNode *child, int newchildindex) β€” slide a child in at a specific index.
  • virtual SoNode * getChild (int index) const β€” grab the child at that index.
  • virtual int findChild (const SoNode *node) const β€” find the index of a given child.
  • virtual int getNumChildren (void) const β€” how many children we got.
  • virtual void removeChild (int childindex) β€” yeet the child at that index.
  • virtual void removeChild (SoNode *child) β€” yeet that specific child.
  • virtual void removeAllChildren (void) β€” yeet everybody. clean slate, no drama 🧹
  • virtual void replaceChild (int index, SoNode *newchild) β€” swap the child at an index for a new one.
  • virtual void replaceChild (SoNode *oldchild, SoNode *newchild) β€” swap an old child for a new one.
  • virtual void getMatrix (SoGetMatrixAction *action) β€” the SoGetMatrixAction flavored entry point.
  • virtual void handleEvent (SoHandleEventAction *action) β€” the SoHandleEventAction flavored entry point.
  • virtual void pick (SoPickAction *action) β€” the SoPickAction flavored entry point.
  • virtual void search (SoSearchAction *action) β€” the SoSearchAction flavored entry point.
  • virtual void write (SoWriteAction *action) β€” the SoWriteAction flavored entry point.
  • virtual SoChildList * getChildren (void) const β€” hands you the whole child list.

🌸 Public Member Functions inherited from SoNode 🌸

  • void setOverride (const SbBool state) β€” flip override mode on or off.
  • SbBool isOverride (void) const β€” are we in override mode? asking for a friend.
  • void setNodeType (const NodeType type) β€” set the node type.
  • NodeType getNodeType (void) const β€” get the node type.
  • virtual SoNode * copy (SbBool copyconnections=FALSE) const β€” make a copy. note the copyconnections=FALSE default, she's off unless you say otherwise.
  • virtual SbBool affectsState (void) const β€” does this node affect state?
  • virtual void grabEventsSetup (void) β€” event grabbing setup.
  • virtual void grabEventsCleanup (void) β€” event grabbing cleanup.
  • virtual void startNotify (void) β€” kick off the notification.
  • uint32_t getNodeId (void) const β€” this node's id number.
  • virtual void writeInstance (SoOutput *out) β€” write out this instance.
  • virtual SoNode * addToCopyDict (void) const β€” add yourself to the copy dictionary.
  • virtual SoFieldContainer * copyThroughConnection (void) const β€” copy through a connection.

πŸ’… Public Member Functions inherited from SoFieldContainer πŸ’…

  • void setToDefaults (void) β€” reset everything back to defaults.
  • SbBool hasDefaultValues (void) const β€” is everything at default values?
  • SbBool fieldsAreEqual (const SoFieldContainer *container) const β€” do our fields match that container's fields?
  • void copyFieldValues (const SoFieldContainer *container, SbBool copyconnections=FALSE) β€” copy field values over, with copyconnections=FALSE by default.
  • SbBool set (const char *const fielddata) β€” set from field data string.
  • void get (SbString &fielddata) β€” get the field data as a string.
  • virtual int getFields (SoFieldList &l) const β€” collect the fields into a list.
  • virtual int getAllFields (SoFieldList &l) const β€” collect all the fields into a list.
  • virtual SoField * getField (const SbName &name) const β€” get a field by name.
  • virtual SoField * getEventIn (const SbName &name) const β€” get an event-in by name.
  • virtual SoField * getEventOut (const SbName &name) const β€” get an event-out by name.
  • SbBool getFieldName (const SoField *const field, SbName &name) const β€” get the name of that field.
  • SbBool enableNotify (const SbBool flag) β€” turn notifications on or off.
  • SbBool isNotifyEnabled (void) const β€” are notifications on?
  • SbBool set (const char *fielddata, SoInput *input) β€” set from field data using an input.
  • void get (SbString &fielddata, SoOutput *out) β€” get field data out through an output.
  • virtual SbBool validateNewFieldValue (SoField *field, void *newval) β€” check a new value for a field.
  • virtual void addWriteReference (SoOutput *out, SbBool isfromfield=FALSE) β€” add a write reference, isfromfield=FALSE unless told otherwise.
  • SbBool getIsBuiltIn (void) const β€” is this thing built in?
  • virtual void getFieldsMemorySize (size_t &managed, size_t &unmanaged) const β€” report memory used by fields, split into managed and unmanaged.
  • void setUserData (void *userdata) const β€” stash your own user data pointer.
  • void * getUserData (void) const β€” get that user data pointer back.

πŸ¦‹ Public Member Functions inherited from SoBase πŸ¦‹

  • void ref (void) const β€” bump the reference count.
  • void unref (void) const β€” drop the reference count.
  • void unrefNoDelete (void) const β€” drop the ref count but don't delete.
  • int32_t getRefCount (void) const β€” what's the ref count rn?
  • void touch (void) β€” touch it, wake the auditors up.
  • SbBool isOfType (SoType type) const β€” are you this type?
  • virtual SbName getName (void) const β€” get the name.
  • virtual void setName (const SbName &newname) β€” set the name.
  • void addAuditor (void *const auditor, const SoNotRec::Type type) β€” add an auditor of that type.
  • void removeAuditor (void *const auditor, const SoNotRec::Type type) β€” remove an auditor of that type.
  • const SoAuditorList & getAuditors (void) const β€” get the auditor list.
  • SbBool shouldWrite (void) β€” should this be written out?
  • void assertAlive (void) const β€” assert that it's alive. dramatic but necessary πŸ’€

🌈 Static Public Member Functions 🌈

  • static SoType getClassTypeId (void) β€” the class type id, statically.
  • static void initClass (void) β€” initialize the class.

🌟 Static Public Member Functions inherited from SoGroup 🌟

  • static SoType getClassTypeId (void) β€” SoGroup's class type id.
  • static void initClass (void) β€” initialize SoGroup.

⭐ Static Public Member Functions inherited from SoNode ⭐

  • static uint32_t getCompatibilityTypes (const SoType &nodetype) β€” compatibility types for a node type.
  • static SoType getClassTypeId (void) β€” class type id.
  • static SoNode * getByName (const SbName &name) β€” find a node by name.
  • static int getByName (const SbName &name, SoNodeList &l) β€” find nodes by name into a list.
  • static void initClass (void) β€” initialize the class.
  • static void initClasses (void) β€” initialize the classes (plural, she's thorough).
  • static uint32_t getNextNodeId (void) β€” the next node id.
  • static int getActionMethodIndex (const SoType type) β€” the action method index for a type.
  • static void getBoundingBoxS (SoAction *action, SoNode *node) β€” static bounding box entry.
  • static void GLRenderS (SoAction *action, SoNode *node) β€” static GL render entry.
  • static void callbackS (SoAction *action, SoNode *node) β€” static callback entry.
  • static void getMatrixS (SoAction *action, SoNode *node) β€” static get matrix entry.
  • static void handleEventS (SoAction *action, SoNode *node) β€” static handle event entry.
  • static void pickS (SoAction *action, SoNode *node) β€” static pick entry.
  • static void rayPickS (SoAction *action, SoNode *node) β€” static ray pick entry.
  • static void searchS (SoAction *action, SoNode *node) β€” static search entry.
  • static void writeS (SoAction *action, SoNode *node) β€” static write entry.
  • static void audioRenderS (SoAction *action, SoNode *node) β€” static audio render entry.
  • static void getPrimitiveCountS (SoAction *action, SoNode *node) β€” static primitive count entry.

πŸ’– Static Public Member Functions inherited from SoFieldContainer πŸ’–

  • static void initClass (void) β€” initialize the class.
  • static SoType getClassTypeId (void) β€” class type id.
  • static void cleanupClass (void) β€” clean the class up.
  • static void initCopyDict (void) β€” set up the copy dictionary.
  • static void addCopy (const SoFieldContainer *orig, const SoFieldContainer *copy) β€” register a copy.
  • static SoFieldContainer * checkCopy (const SoFieldContainer *orig) β€” check for a copy.
  • static SoFieldContainer * findCopy (const SoFieldContainer *orig, const SbBool copyconnections) β€” find a copy, with a copyconnections flag.
  • static void copyDone (void) β€” copying's done, wrap it up.

🧚 Static Public Member Functions inherited from SoBase 🧚

  • static void initClass (void) β€” initialize the class.
  • static SoType getClassTypeId (void) β€” class type id.
  • static void addName (SoBase *const base, const char *const name) β€” give a base a name.
  • static void removeName (SoBase *const base, const char *const name) β€” take that name away.
  • static void incrementCurrentWriteCounter (void) β€” bump the current write counter.
  • static void decrementCurrentWriteCounter (void) β€” drop the current write counter.
  • static SoBase * getNamedBase (const SbName &name, SoType type) β€” get a named base of that type.
  • static int getNamedBases (const SbName &name, SoBaseList &baselist, SoType type) β€” get named bases into a list, of that type.
  • static SbBool read (SoInput *input, SoBase *&base, SoType expectedtype) β€” read a base from input, expecting a type.
  • static void setInstancePrefix (const SbString &c) β€” set the instance prefix string.
  • static void setTraceRefs (SbBool trace) β€” turn ref tracing on or off.
  • static SbBool getTraceRefs (void) β€” is ref tracing on?
  • static SbBool connectRoute (SoInput *input, const SbName &fromnodename, const SbName &fromfieldname, const SbName &tonodename, const SbName &tofieldname) β€” wire up a route from node+field to node+field.
  • static SbBool readRoute (SoInput *input) β€” read a route from input.

πŸ‘‘ Public Attributes πŸ‘‘

  • SoMFFloat range β€” the range field. the whole point of this node tbh.
  • SoSFVec3f center β€” the center field, a 3D vector.

πŸŽ€ Protected Member Functions πŸŽ€

  • virtual const SoFieldData * getFieldData (void) const β€” grab the field data.
  • virtual ~SoLOD () β€” the destructor. rest in peace, queen πŸ•ŠοΈ
  • virtual int whichToTraverse (SoAction *) β€” the actual decision-maker: which child do we traverse? the iconique core logic ✨

πŸ’œ Protected Member Functions inherited from SoGroup πŸ’œ

  • virtual ~SoGroup () β€” destructor.
  • virtual SbBool readInstance (SoInput *in, unsigned short flags) β€” read an instance in.
  • virtual SbBool readChildren (SoInput *in) β€” read the children in.
  • virtual void copyContents (const SoFieldContainer *from, SbBool copyconnections) β€” copy the contents over, with the copyconnections flag.

🌸 Protected Member Functions inherited from SoNode 🌸

  • SoNode (void) β€” constructor.
  • virtual ~SoNode () β€” destructor.

πŸ’… Protected Member Functions inherited from SoFieldContainer πŸ’…

  • SoFieldContainer (void) β€” constructor.
  • virtual ~SoFieldContainer () β€” destructor.

πŸ¦‹ Protected Member Functions inherited from SoBase πŸ¦‹

  • SoBase (void) β€” constructor.
  • virtual ~SoBase () β€” destructor.
  • virtual void destroy (void) β€” destroy it.
  • SbBool hasMultipleWriteRefs (void) const β€” does it have multiple write refs?
  • SbBool writeHeader (SoOutput *out, SbBool isgroup, SbBool isengine) const β€” write the header, given group/engine flags.
  • void writeFooter (SoOutput *out) const β€” write the footer.
  • virtual const char * getFileFormatName (void) const β€” the file format name.

🌈 Static Protected Member Functions 🌈

  • static const SoFieldData ** getFieldDataPtr (void) β€” the field data pointer pointer. yes, double pointer. iconic.

🌟 Static Protected Member Functions inherited from SoGroup 🌟

  • static const SoFieldData ** getFieldDataPtr (void) β€” SoGroup's field data pointer pointer.

⭐ Static Protected Member Functions inherited from SoNode ⭐

  • static const SoFieldData ** getFieldDataPtr (void) β€” field data pointer pointer.
  • static void setNextActionMethodIndex (int index) β€” set the next action method index.
  • static int getNextActionMethodIndex (void) β€” get the next action method index.
  • static void incNextActionMethodIndex (void) β€” increment the next action method index.
  • static void setCompatibilityTypes (const SoType &nodetype, const uint32_t bitmask) β€” set compatibility types with a bitmask.

🧚 Static Protected Member Functions inherited from SoBase 🧚

  • static uint32_t getCurrentWriteCounter (void) β€” the current write counter.
  • static void staticDataLock (void) β€” lock the static data.
  • static void staticDataUnlock (void) β€” unlock the static data.

πŸ’– Additional Inherited Members πŸ’–

πŸŽ€ Public Types inherited from SoNode πŸŽ€

enum NodeType { INVENTOR = 0x0000, VRML1 = 0x0001, VRML2 = 0x0002,
    INVENTOR_1 = 0x0004, INVENTOR_2_0 = 0x0008, INVENTOR_2_1 = 0x0010,
    INVENTOR_2_5 = 0x0020, INVENTOR_2_6 = 0x0040, COIN_1_0 = 0x0080,
    COIN_2_0 = 0x0100, EXTENSION = 0x0200, COIN_2_2 = 0x0400, COIN_2_3 =
    0x0800, COIN_2_4 = 0x1000, INVENTOR_5_0 = 0x2000, COIN_2_5 = 0x4000,
    COIN_3_0 = 0x8000, INVENTOR_6_0 = 0x10000 }

look at all those node types. every single one, exactly as written, no cap πŸ’…


πŸ’œ Protected Types inherited from SoBase πŸ’œ

enum BaseFlags { IS_ENGINE = 0x01, IS_GROUP = 0x02 }

🌸 Protected Attributes inherited from SoGroup 🌸

  • SoChildList * children β€” the children, right there in the open (well, protected).

πŸ’… Protected Attributes inherited from SoNode πŸ’…

  • uint32_t uniqueId β€” the unique id, living its best protected life.

πŸ¦‹ Protected Attributes inherited from SoFieldContainer πŸ¦‹

  • SbBool isBuiltIn β€” is it built in?

⭐ Static Protected Attributes inherited from SoNode ⭐

  • static uint32_t nextUniqueId = 1 β€” starts at 1, bestie.
  • static int nextActionMethodIndex = 0 β€” starts at 0.

that's the whole member-list portion, and there's more coming β€” part 2 is on the way, don't go anywhere 🫢

Detailed Description πŸ’–

okay so bestie, the SoLOD class? It's literally here to pick a child based on the distance between the viewer and the object. no cap. πŸ’…

and like, the docs for SoLOD are similar enough to SoLevelOfDetail that we're gonna send you to look at that one first. It explains the whole level-of-detail thing: what it is, why you'd use it, how to use it. go read it, it's giving tutorial energy. ✨

the tea: main difference between SoLOD and SoLevelOfDetail is that SoLOD uses the speedier "distance-to-viewer" technique for implementing level-of-detail functionality, while SoLevelOfDetail uses the more correct (but potentially slower) "projected-bbox-area" technique. so SoLOD is fast, SoLevelOfDetail is accurate. pick your fighter. πŸ₯Š

here's a mockup example (in Inventor file format style, but easily converted to code) that shows how to use this node:

LOD {
   range [ 10, 20, 30, 40 ]

   Sphere { }
   Cylinder { }
   Cone { }
   Cube { }
   Info { }
}

so for that sub-scenegraph: when the LOD-object is less than 10 units away from the viewpoint camera, an SoSphere will be shown. For distances 10 - 20 units away, this will be changed to the SoCylinder, and so on. For distances of more than 40 units from the camera, an SoInfo node will be traversed / rendered -- ie, nothing will be shown. (this is a common "trick" used to optimize rendering when models get far enough away from the camera that we want to remove them completely. bye felicia. πŸ’€)

⚠️ note bestie: when using an SoOrthographicCamera in the examiner viewers of the SoQt, SoWin and SoXt libraries, it will seem like the SoLOD node is not working when using the "Zoom" functionality. What happens is that an SoOrthographicCamera is not actually moved, the "zoom" effect is accomplished simply by changing its height-of-view setting (i.e. the value of the SoOrthographicCamera::height field), but its position remains constant. So the distance to the camera will not change, which means SoLOD will pick the same child, no matter how much one "zooms". it's giving illusion. πŸ™ˆ

(the SoLevelOfDetail node uses the screen space area of the object to decide when to switch children, so that node will still work with SoOrthographicCamera. so if you need ortho zoom, use that one. πŸ’…)

FILE FORMAT/DEFAULTS πŸ’Ύ

LOD {
    center 0 0 0
    range [  ]
}

Since πŸ•°οΈ

Inventor 2.1

See also πŸ‘€

SoLevelOfDetail


Constructor & Destructor Documentation πŸ› οΈ

SoLOD::SoLOD (void )

Default constructor. no args, just vibes. ✨

SoLOD::SoLOD (int numchildren)

Constructor.

The argument should be the approximate number of children which is expected to be inserted below this node. The number need not be exact, as it is only used as a hint for better memory resource allocation. so like, give it a guess, it's not that deep. πŸ’…

SoLOD::~SoLOD () [protected], [virtual]

Destructor. protected and virtual, so it's doing its thing behind the scenes. 🫢


Member Function Documentation 🧠

SoType SoLOD::getTypeId (void ) const [virtual]

Returns the type identification of an object derived from a class inheriting SoBase. This is used for run-time type checking and "downward" casting. basically: who dis? and can I safely cast you? πŸ‘‘

Usage example:

void foo(SoNode * node)
{
  if (node->getTypeId() == SoFile::getClassTypeId()) {
    SoFile * filenode = (SoFile *)node;  // safe downward cast, knows the type
  }
}

For application programmers wanting to extend the library with new nodes, engines, nodekits, draggers or others: this method needs to be overridden in all subclasses. This is typically done as part of setting up the full type system for extension classes, which is usually accomplished by using the pre-defined macros available through for instance Inventor/nodes/SoSubNode.h (SO_NODE_INIT_CLASS and SO_NODE_CONSTRUCTOR for node classes), Inventor/engines/SoSubEngine.h (for engine classes) and so on. it's giving boilerplate but make it cute. πŸ’…

For more information on writing Coin extensions, see the class documentation of the toplevel superclasses for the various class groups. iykyk.

Reimplemented from SoGroup. periodt.

const SoFieldData * SoLOD::getFieldData (void ) const [protected], [virtual]

Returns a pointer to the class-wide field data storage object for this instance. If no fields are present, returns NULL. so if you got no fields, you get nothing. πŸ’€

Reimplemented from SoGroup.

void SoLOD::doAction (SoAction * action) [virtual]

This function performs the typical operation of a node for any action. it's the default behavior, bestie. ✨

Reimplemented from SoGroup.

void SoLOD::callback (SoCallbackAction * action) [virtual]

Action method for SoCallbackAction.

Simply updates the state according to how the node behaves for the render action, so the application programmer can use the SoCallbackAction for extracting information about the scene graph. so it's like a little spy for your scene graph. πŸ•΅οΈ

Reimplemented from SoGroup.

void SoLOD::GLRender (SoGLRenderAction * action) [virtual]

Action method for the SoGLRenderAction.

This is called during rendering traversals. Nodes influencing the rendering state in any way or who wants to throw geometry primitives at OpenGL overrides this method. so if you're bossing around OpenGL, you override this. πŸ”₯

Reimplemented from SoGroup.

void SoLOD::GLRenderBelowPath (SoGLRenderAction * action) [virtual]

Implements the SoAction::BELOW_PATH traversal method for the rendering action.

Reimplemented from SoNode.

void SoLOD::GLRenderInPath (SoGLRenderAction * action) [virtual]

Implements the SoAction::IN_PATH traversal method for the rendering action.

Reimplemented from SoNode.

void SoLOD::GLRenderOffPath (SoGLRenderAction * action) [virtual]

Implements the SoAction::OFF_PATH traversal method for the rendering action.

Reimplemented from SoNode.

void SoLOD::rayPick (SoRayPickAction * action) [virtual]

Action method for SoRayPickAction.

Checks the ray specification of the action and tests for intersection with the data of the node. so it's like, is this ray hitting you? πŸ‘€

Nodes influencing relevant state variables for how picking is done also overrides this method.

Reimplemented from SoNode.

void SoLOD::getBoundingBox (SoGetBoundingBoxAction * action) [virtual]

Action method for the SoGetBoundingBoxAction.

Calculates bounding box and center coordinates for node and modifies the values of the action to encompass the bounding box for this node and to shift the center point for the scene more towards the one for this node.

Nodes influencing how geometry nodes calculates their bounding box also overrides this method to change the relevant state variables.

Reimplemented from SoGroup.

void SoLOD::getPrimitiveCount (SoGetPrimitiveCountAction * action) [virtual]

Action method for the SoGetPrimitiveCountAction.

Calculates the number of triangle, line segment and point primitives for the node and adds these to the counters of the action.

Nodes influencing how geometry nodes calculates their primitive count also overrides this method to change the relevant state variables.

Reimplemented from SoGroup.

void SoLOD::audioRender (SoAudioRenderAction * action) [virtual]

Action method for SoAudioRenderAction.

Does common processing for SoAudioRenderAction action instances.

Reimplemented from SoGroup.

void SoLOD::notify (SoNotList * l) [virtual]

Notifies all auditors for this instance when changes are made. so it's like a group chat notification. πŸ“£

Reimplemented from SoNode.

int SoLOD::whichToTraverse (SoAction * action) [protected], [virtual]

Returns the child to traverse based on the ranges in SoLOD::range. Will clamp to index to the number of children. This method will return -1 if no child should be traversed. This will only happen if the node has no children though. so if you got no kids, you get -1. πŸ’€


Member Data Documentation πŸ“¦

SoMFFloat SoLOD::range

The distance ranges which decides when to use each child for traversal / rendering. See usage example in main class documentation of SoLOD for an explanation of how this vector should be set up correctly.

By default this vector just contains a single value 0.0f. so it's like a list of distance cutoffs. ✨

SoSFVec3f SoLOD::center

This vector represents an offset within the object from the geometric center point to the center point the application programmer would actually like the distance between the viewer and the object to be calculated from.

Default value is [0, 0, 0]. It is usually not necessary to change this field. so just leave it, bestie. 🫢


Author πŸ‘‘

Generated automatically by Doxygen for Coin from the source code. so it's not a human, it's Doxygen. respect. πŸ’…


πŸ’– that's the whole page, bestie! this came from Coin, Version 3.1.3, and the page is SoLOD(3). now go forth and LOD responsibly. periodt. πŸ’…βœ¨

πŸ“¦ where this page comes from