Jump to content
The Dark Mod Forums

Recommended Posts

Continued from the MapExpressions thread.

I just found some time to take a brief look into the speaker radius task. And already some questions arrise ;-)

Why is it called radius (speaking of lights)? My Radiant shows squares and not circles...

The light radius/box drawing code is in plugins/entity/light/Renderables.h/cpp and really doesn't look big (is that everything?). So "copying" that over to speaker is everything?

On first quick search I couldn't find the speaker code. Where is it hiding (I guess it isn't as nicely seperated as the light code...)

Should I just bump the new code into the existing files or create seperate ones just like the light files?

The entity inspector doesn't show a speaker radius, speakers do have a radius, do they? Otherwise the task really doesn't make sense...

 

Surely more to come ;-)

Link to post
Share on other sites
  • Replies 123
  • Created
  • Last Reply

Top Posters In This Topic

The speaker radii are defined in the soundshader files (sound/*.sndshd). There is a minDistance/maxDistance setting in the sound shader definition, which defines the shape of the sound volume. These will have to be parsed, the sound shaders are referred to by the "s_shader" spawnarg on the speaker entity. There is a sound manager module which will have to be extended to deliver this min/max information.

 

Lights don't have a round shape in terms of a sphere, "radius" is not the correct word for this, I reckon. I think this is a remnant of Quake 3, where lights did have a spherical shape (but I might be wrong here). Still, the extents of the light volume are referred to as "radius".

 

The speaker is not a class on its own. It will be "incorporated" in a GenericEntityNode, which has the classname "speaker" (spawnclass "idSound"). You will have to detect these classnames in the spawnargs of the GenericEntity classes and submit a Renderable to the ShaderCache. This renderable will get invoked during the backend rendering process (virtual void render()). This code will call the actual OpenGL commands and draw the circles. For this you can probably define a new object class SpeakerRadius : public OpenGLRenderable, which will be submitted by the GenericEntityInstance. The code for this can partially be copied from the light radius stuff, but has to be adapted to actually draw a circle. And yes, most OpenGL call sequences are relatively short, depending on the type of commands (glVertex*() sequences, vertex arrays, buffer objects, display lists).

 

Does this help?

Link to post
Share on other sites

It would be better to create a new C++ class to correspond to a renderable speaker (as the Light does), rather than attaching dedicated render classes to GenericEntity. After all, it is not a generic entity which is why the special handling is needed.

 

Ideally there should be some regex-matching from keys in the .game file which is used to determine which entity subclass is used, rather than hardcoded values, but just checking for "speaker" would be acceptable as a first solution.

Link to post
Share on other sites
Yeah, I guess that should get me started, thanks.

 

One more: What does MinDistance mean?

The sound can be heard with full volume if you are closer to the speaker than the mindistance. Maxdistance is the maximum distance where the sound can be heard at all.

The next problem is that the distances are not given in Doomunits, but I think in meters (approximately), therefore the values are quite small.

Link to post
Share on other sites

I suggest using the Light classes as a starting point, they are more recent and probably contain less GtkRadiant cruft, as well as being closer to the required behaviour (except they have a square "radius" rather than a round one).

Link to post
Share on other sites

The GenericEntity might not be that bad a guess, as the light classes are really cramped with light-specific stuff. The GenericEntiy* classes are pretty small, so it might be best to take a look at both and see for yourself.

Link to post
Share on other sites

Yes, it's perfectly possible for a soundshader to reference multiple sound files. This can be used to have a variation of footstep sounds that get played in random order, for instance.

Link to post
Share on other sites

Which file are you exactly searching for?

 

(The Light classes are located in plugins/entity/light/*, the generic entity classes are in plugins/entity/generic/*.)

Link to post
Share on other sites

I think he's talking about which file is responsible for determining which C++ class to instantiate for each type of entity. A cursory look suggests that EntityCreator::getEntityForEClass in EntityCreator.cpp would be the place to start.

 

(Although I guess he might be asking about the SConscript as well)

Link to post
Share on other sites

Okay, now I'm sorta stuck on creating the actual speakerEntity.

I have changed the SoundShader to contain min/max and SoundManager to fill those values.

I have also created the Speaker class.

But creating the entity seems to be a quite complex process involving the vfs (I guess this means virtual file system) in plugins/eclassmgr/eclass_doom3.cpp.

I guess the vfs is filled up with the Shaders (no idea where) and afterwards the EntityClassDoom3 creates the entities with those .def files in the vfs.

Could someone clear this up a bit?

Link to post
Share on other sites

Take a look at plugins/entity/EntityCreator.cpp. The method getEntityForEClass(IEntityClassPtr eclass) takes an entity class pointer and creates the according Node for it. This is where you have to place your hook:

 

In this method, you take the EClass and query its name ("classname"). If the name == "speaker", you can return a new scene::INodePtr(new SpeakerNode()).

 

If you have already edited the SoundManager to parse the min/max values, I guess that's fine enough for the moment. The EntityCreator doesn't want to mess with the actual Shaders, neither with the VFS. All that matters is the classname and the SpeakerNode classes will take care of the details.

 

(Also, if you like you can send me a diff with the SoundManager changes, as these are presumably self-consistent enough so that I can commit it.)

Link to post
Share on other sites

Actually I added a isSpeaker() and setIsSpeaker() function to correspond to the isLight()/setIsLight() function. Those are set in plugins/eclassmgr/eclass_doom3.cpp, which does deal with the vfs.

Just checking for name == "speaker" sounds less complicate of course.

 

The SoundManager changes are tival, if you think those are worth committing, I can upload a diff.

The two problematic points are the transformation from the SoundShader to the final SoundEntityNode and the SoundEntity itself, which I sort of just trial-and-error merged from genericEntity class and Light class as I didn't want to read through all those inherited classes.

Link to post
Share on other sites

Anything that is an improvement over the current codebase (and is stable code) is worth committing. It sounds that your local version of the SoundManager is an improved one - so yes, please post a diff. :) It also keeps the revisions clear. Several small improvement steps are better than one large step where 30 files are being changed at the same time. (I learned that the hard way.)

Link to post
Share on other sites

Well then, this is the patch with the SoundManager changes: soundManager.diff.

I only briefly tested it (copied changes over to clean checkout, got it to compile, one test run), but I guess it works.

 

I think I'll restart with the Speaker class with a 1:1 copy of genericEntity. Since then it'll compile and work for once. I think I won't get anywhere when I continue to mix the light and genericEntity class without understanding what I do... <_<

 

Oh, should I now actually go with the name == "speaker" check?

Link to post
Share on other sites

Thanks for the diff, I'll check it out. :)

 

There is only one specific speaker entity in the Doom 3 game, so I think that check would be fine. The best place for such game-specific constants is the doom3.game file (i.e. the XMLRegistry) anyway, but this can be moved there later on as well.

Link to post
Share on other sites

Committed. The only thing I changed was the argument type for setSoundRadii():

void setSoundRadii(const SoundRadii& soundRadii)

It's almost always ok to pass non-primitive structure (like std::string, structures and such) by reference instead of by value. Otherwise there is an additional call to the SoundRadii constructor involved. Minor nitpick of course, just thought I'd mention it. :)

Link to post
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.


×
×
  • Create New...