Jump to content
The Dark Mod Forums

Speaker radius

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

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

    • MayheM

      Hello, Since this track is originally from TDM,i think it's better to ask here than TTLG. Do you guys have the full version of this ambient track?
      · 2 replies
    • DeTeEff

      Bachelor Mapping Challenge!
      The girlfriend will be away to her mum's place for almost a week, which means more mapping time for me! I'm planning a speed build. Hope it will go my way
      I'm starting by downloading 2.11. Don't know if I'm going to use any fancy new stuff. Just want to crack those itching map muscles that has gone dry and dead since almost a year's worth of no-mapping
      · 4 replies
    • kano

      The cool part of Canonical's Snap, is that my machine can now ray-trace an entire (simple) scene faster than it takes the web browser to start!
      · 5 replies
    • datiswous

      Fm idea (braindump)
      "Experience the life of a mission builder"
      Esentially there are finnished elements placed somewhere in storage in the game and you have to place them in the correct places, build some walls here and there, add guard routes, give them their correct speech lines, etc. Decorate the places.. all in-game. lots of fun.. 😉
      If you do it right in the end you can play the mission.
      (would be even cooler if a thief-ai could play the mission, making it some kind of tower-defence game)
      This first started as an idea for an aquarium builder mission where-in you have to fill an empty aquarium with sand, waterplants, castles water and swimming fish. But above idea is more fun.
      · 4 replies
    • JackFarmer

      Dear ChatGPT, What are The Builders in the Dark Mod?
      The Builders is a popular game mode in the video game community called "Dark Mod," which is a fan-made tribute to the classic "Thief" series of stealth games. In this game mode, players assume the role of builders who construct structures in a dark and ominous environment while trying to avoid detection by patrolling guards.
      The Builders game mode is unique in that it offers players the opportunity to create and design their own levels using the in-game tools and resources provided. Players can experiment with different building materials, construct intricate traps and puzzles, and create their own unique gameplay experiences.
      While The Builders game mode is not an official part of the Dark Mod, it has become one of the most popular and well-loved aspects of the game, thanks to its emphasis on creativity, strategy, and stealth.
      You guys did not know that, did you?
      · 2 replies
  • Create New...