Jump to content
The Dark Mod Forums

Recommended Posts

Posted

I work since a week or so, so my time is limited. But I can surely try another task.

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

  • Replies 314
  • Created
  • Last Reply

Top Posters In This Topic

Posted

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".

Posted

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.

Posted

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?

Posted

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. ;)

Posted

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.

Posted

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.

Posted

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?

Posted

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.

Posted

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.

Posted

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...)

Posted

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?

Posted

Wait a moment, why did the model show up when it was never inserted into the tree?

 

Edit: Now it shows:

libs/instancelib.h:183
assertion failure: InstanceSet::insert - element already exists

Posted

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.

Posted

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*.

Posted

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.

Posted

That function is not listed in the .h file and is called by Scene_BrushResize_Selected. If changing that is fine then ConstruchtCuboid is the best choice I guess.

Posted

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).

Posted

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. :)

Posted

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.

Posted

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.

Posted

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.

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

    • JackFarmer

      "The Year of the Rat." 
      😄

      Al Stewart must be proud of you!
      Happy testing!
      @MirceaKitsune
      · 1 reply
    • datiswous

      I posted about it before, but I think the default tdm logo video looks outdated. For a (i.m.o.) better looking version, you can download the pk4 attached to this post and plonk it in your tdm root folder. Every mission that starts with the tdm logo then starts with the better looking one. Try for example mission COS1 Pearls and Swine.
      tdm_logo_video.pk4
      · 2 replies
    • JackFarmer

      Kill the bots! (see the "Who is online" bar)
      · 3 replies
    • STiFU

      I finished DOOM - The Dark Ages the other day. It is a decent shooter, but not as great as its predecessors, especially because of the soundtrack.
      · 5 replies
×
×
  • Create New...