Jump to content
The Dark Mod Forums

MapExpressions


Recommended Posts

  • Replies 314
  • Created
  • Last Reply

Top Posters In This Topic

If possible something in space would be interesting, but it's not that important.

 

I'd quite like to do something in space as well, but I think the lack of Internet connectivity and disorienting zero gravity might get in the way slightly. :laugh:

Link to comment
Share on other sites

Hm, maybe this would be something appropriate? Bounding Box Creation for models. It's currently assigned to OrbWeaver, so I don't know if he rather wants to do it himself?

 

I think this can also be useful for models already existing in the map. A la: select a model > right-click > "Create Monster Clip Brush".

Link to comment
Share on other sites

That certainly needs doing. There are two components for that feature:

 

1. Ensure that there is a means for the BrushCreator (or whatever is currently responsible for creating new brushes) to generate a new brush from an arbitrary AABB. You might need a function like BrushCreator::createFromAABB(const AABB& aabb) to do this.

2. Add an option to the Model Selector dialog to create a monsterclip brush using the AABB of the created model. I suggest some kind of "Advanced" section or dialog, with this option as well as the other needed model creation options such as noshadows.

 

Greebo's menu option would also be useful.

Link to comment
Share on other sites

After programming 5 hours or so I noticed that my approach on the "add bounding box" checkbox can't work out.

 

The ModelSelector just returns a Model and a Skin name.

Everything else has to be done by the caller.

So a tick box "create bounding box" would have to be evaluated by the caller too.

 

My approach was to change ModelSelector into a "normal" singleton class with a getInstance function. I also added another function that returned the state of the "create bounding box" checkbox. After changing the Ortho Menu to use the new interface and evaluate the new option I noticed that the Ortho Menu isn't the only one that uses the ModelSelector. Reimplementing the evaluation of the options everywhere the ModelSelector is used seems stupid, especially when even more options are added.

 

Any ideas how to solve that in an elegant way?

Link to comment
Share on other sites

Here, it's probably best to leave the ModelSelector non-singleton, so that multiple clients can use it. I haven't checked how it's implemented now, but it's usually enough to add a getWidget() method to the class, so that it can be packed into any parent container. An example for this is the ShaderSelector class, which is used by the LightInspector, the Find & Replace dialog and so on.

 

Each client which wants to feature a ModelSelector, would instantiate a separate ModelSelector class and pack it into its own dialog, adding any widgets that are necessary in addition to the pure ModelSelecor.

 

If the instantiation of multiple ModelSelector objects is expensive in terms of loading time and memory, we could take the approach of out-sourcing the model treestore into a singleton class, so that the models have to be loaded only once.

 

Please feel free to ask, if I didn't explain it properly or if I talked rubbish. ;)

Link to comment
Share on other sites

It shouldn't need to be that complex, the clients don't have to worry about GTK widgets themselves. All they are interested in is a single boolean value to indicate whether the bounding box brush should be created or not.

 

For this, I recommend expanding the ModelAndSkin struct into a more generic ModelCreationSettings object which, in addition to the skin and model name, includes a boolean value indicating the state of the checkbox. This can then be enhanced in future with whatever other ancillary options are required.

Link to comment
Share on other sites

OrbWeaver: Your approach worked out very well, since it is backwards compatible (so I don't have to change all callers at once).

 

One more question, how can I retrieve a model from a node? I guess with localAABB() I can then get it's AABB.

Link to comment
Share on other sites

You can try to cast the Node onto an EntityNode and check the spawnargs (name != model && !name.empty()).

 

There is no ModelNode you can dynamic_cast the scene::INodePtr onto currently, I think.

 

What do you need exactly?

Link to comment
Share on other sites

ModelSelectorResult ms = ui::ModelSelector::chooseModel();

	// If a model was selected, create the entity and set its model key
	if (!ms.model.empty()) {
		try {
		scene::INodePtr node = Entity_createFromSelection(MODEL_CLASSNAME,
															 self->_lastPoint);
		Node_getEntity(node)->setKeyValue("model", ms.model);
		Node_getEntity(node)->setKeyValue("skin", ms.skin);

		// If 'createClip' is ticked, create a clip Brush
		if (ms.createClip) {
			scene::INodePtr node(GlobalBrushCreator().createBrush());
			Node_getTraversable(GlobalMap().findOrInsertWorldspawn())->insert(node);

			scene::Path brushpath(GlobalSceneGraph().root());
			brushpath.push(GlobalMap().getWorldspawn());
			brushpath.push(node);
			selectPath(brushpath, true);

			Scene_BrushResize_Selected(GlobalSceneGraph(),
										//AABB (Vector3(1,2,3),Vector3(1,1,1)),
										.localAABB(),
										"textures/common/monster_clip");
										//AABB::createFromMinMax(mins, maxs),
		}

I need to get the AABB of that model for Scene_BrushResize_Selected.

 

btw. Is there an easier way to create a brush, I don't really understand what all those commands do, I just copied them from XYWnd.cpp.

Link to comment
Share on other sites

I see what you need now. You can call the Instance::worldAABB() method for this. Retrieving the instance from the node is not trivial, but part of the code is already there, so you can reuse it. You'll need a scene::Path to lookup the newly created Instance:

		scene::Path brushpath(GlobalSceneGraph().root());
	brushpath.push(GlobalMap().getWorldspawn());
	brushpath.push(node);

This brushPath object can be used to find the instance. Try this (include scenelib.h):

	scene::Instance& instance = findInstance(brushPath);
AABB brushAABB(instance.worldAABB());

This will give you a reference to the newly created BrushInstance. Once you have the instance, you can call worldAABB() to retrieve the bounds.

 

The brush creation code is ok. It can of course be simplified, but basically it's always this way: Create a node, insert it into the parent scene::Traversable (which triggers instantiation). Done.

Link to comment
Share on other sites

I sort-of understand it only a little bit better now, this IS complicated...

		ModelSelectorResult ms = ui::ModelSelector::chooseModel();
	// If a model was selected, create the entity and set its model key
	if (!ms.model.empty()) {
		try {
		scene::INodePtr modelNode = Entity_createFromSelection(MODEL_CLASSNAME,
															 self->_lastPoint);
		Node_getEntity(modelNode)->setKeyValue("model", ms.model);
		Node_getEntity(modelNode)->setKeyValue("skin", ms.skin);

		// If 'createClip' is ticked, create a clip Brush
		if (ms.createClip) {

			// get the model
			scene::Path brushPath(GlobalSceneGraph().root());
			brushPath.push(GlobalMap().getWorldspawn());
			brushPath.push(modelNode);
			scene::Instance& instance = findInstance(brushPath);
			// retrieve the AABB
			AABB brushAABB(instance.worldAABB());

			scene::INodePtr brushNode(GlobalBrushCreator().createBrush());
			Node_getTraversable(GlobalMap().findOrInsertWorldspawn())->insert(brushNode);
			Scene_BrushResize_Selected(GlobalSceneGraph(),
										brushAABB,
										"textures/common/monster_clip");
		}

This segfaults because findInstance finds nothing.

Could it be that Scene_BrushResize_Selected only works on the Brush visually selected in the XY view? Then that function is totally misplaced there. (and that function seems not to use the first argument...)

Link to comment
Share on other sites

The modelNode is never inserted and hence never instantiated. You'll have to insert it as child of scenegraph root (which is the only valid location in the scenegraph btw, all entities have to be children of root):

scene::INodePtr modelNode = Entity_createFromSelection(MODEL_CLASSNAME,
										 self->_lastPoint);
Node_getTraversable(GlobalScenegraph().root())->insert(modelNode);

Does this work?

Link to comment
Share on other sites

Ok, seems like the node is already inserted somewhere, probably by the Entity_createFromSelection() routine.

 

Wait, the brushPath in the above code (which should be named modelPath btw) is not correct. It should be like this:

scene::Path brushPath(GlobalSceneGraph().root());
brushPath.push(modelNode);

Because the model is contained in an entity which is always child of the map root.

Link to comment
Share on other sites

It seems that this first part of the code works now. But no brush is created and on drag it shows

Warning: removed degenerate brush!

I replaced the AABB in Scene_BrushResize_Selected with a manually constructed one and it still shows the same message. So I guess that Scene_BrushResize_Selected doesn't work. I think this function is not intended for this purpose, perhaps I find a better one.

I'll take a look tomorrow *yawn*.

Link to comment
Share on other sites

You might want to take a look at Brush_ConstructCuboid in brushmanip.cpp. This appears to resize an existing brush to fit the given AABB. It requires an existing brush as argument.

 

edit: scrap that, I think I know what the problem with the above code is. The Scene_BrushResize_Selected routine requires the target brush to be selected, so you'll have to call selectPath() on the brush path (not the modelPath) first.

Link to comment
Share on other sites

Woho, I got it to work.

Even though I wrote another function that calls ConstructCuboid more directly than Scene_BrushResize_Selected. That function was to suspicious to me, since visually selecting a brush to operate on it seems wrong.

 

And worldAABB returned the wrong AABB for small models. childBounds produces correct results. But I have no idea what the difference is, I just did some trial-and-error.

 

Now I'm thinking if it would make sense to add a way to hide or gray out the option, since in some cases adding a bounding box doesn't make sense (eg. when changing the model).

Link to comment
Share on other sites

If the worldAABB is not producing desirable results, you can try to cast the Instance onto a Bounded object and retrieve the bounding box via localAABB(). This is what should be happening when you call worldAABB() too, but you can never be sure with the Radiant codebase. ;)

 

Anyway, good to see you're making progress. :)

Link to comment
Share on other sites

As I said, the childBounds() returns the correct AABB (no idea what the difference is).

 

In radiant/selection/algorithm/Primitives.cpp in createCMFromSelection() the ModelSelector is also used, but I have no idea where this function is actually used in DarkRadiant. Could you tell me where this feature (what ever it might be) hides?

 

I think I will hide the "create bounding box" option when called from the ModelPropertyEditor.

Link to comment
Share on other sites

The createCMFromSelection() is the Collision Model export function. It is linked to a Command in the EventManager, which means that it can be called via the Menu items and the Toolbar buttons. The link is established here:

 

GlobalEventManager().addCommand(
"BrushExportCM", 
FreeCaller<selection::algorithm::createCMFromSelection>()
);

 

This method doesn't need to display the "create monsterclip" option, if that's what you want to know.

Link to comment
Share on other sites

Should I grey out the options seperately (keeps them still ticked which could cause some confusion) or hide them altogether (prevents showing only some of the options)?

 

Edit: greying them out seperately can make the function inverface quite bloated once more functions are added.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recent Status Updates

    • Petike the Taffer  »  DeTeEff

      I've updated the articles for your FMs and your author category at the wiki. Your newer nickname (DeTeEff) now comes first, and the one in parentheses is your older nickname (Fieldmedic). Just to avoid confusing people who played your FMs years ago and remember your older nickname. I've added a wiki article for your latest FM, Who Watches the Watcher?, as part of my current updating efforts. Unless I overlooked something, you have five different FMs so far.
      · 0 replies
    • Petike the Taffer

      I've finally managed to log in to The Dark Mod Wiki. I'm back in the saddle and before the holidays start in full, I'll be adding a few new FM articles and doing other updates. Written in Stone is already done.
      · 4 replies
    • nbohr1more

      TDM 15th Anniversary Contest is now active! Please declare your participation: https://forums.thedarkmod.com/index.php?/topic/22413-the-dark-mod-15th-anniversary-contest-entry-thread/
       
      · 0 replies
    • JackFarmer

      @TheUnbeholden
      You cannot receive PMs. Could you please be so kind and check your mailbox if it is full (or maybe you switched off the function)?
      · 1 reply
    • OrbWeaver

      I like the new frob highlight but it would nice if it was less "flickery" while moving over objects (especially barred metal doors).
      · 4 replies
×
×
  • Create New...