Jump to content
The Dark Mod Forums
Sign in to follow this  
STiFU

Understanding the Code

Recommended Posts

Hey, I just thought that if I detect definition duplicates anyway, I should also provide a method to retrieve those definitions and the files they are stored in. And then I thought, if I do that, I should also provide methods for retrieving sorted lists of all found definitions and all .xd-files. So now, we could let the user choose to import a specified definition or a whole file and we have a little more debug-output.

Share this post


Link to post
Share on other sites

Here's the first small (visible) success to report - the GuiRenderer is already able to render the background images of the GUI windowDef hierarchy, including alpha blending (the screenie shows the tdm_objectives.gui)

 

readable_editor.jpg

 

Next up on the list is the font rendering.

Share this post


Link to post
Share on other sites

Regarding the font rendering: Do the GUIs of Doom support different textalignments? That would basically be a feature that needs to be integrated into XData-definitions as well.

 

By the way, I think the name RenderableFont was much more suitable for your class than RenderableText, as the latter suggests that we are dealing with an actual text here instead of a font. An XData-Object with render-support would rather be a RenderableText.

 

I also just had an idea for the two importer methods. As I said they currently return a copy of an XData-object respectively a list of XData-objects. Passing those as a reference would not only get rid of the copy-constructor-calls, but I could also make an exception-free implementation then by returning a bool and appending the import-breaking errormessage to the errormessagelist. I leave it up to you. Would you rather like to catch an exception or have a boolean returned?

Share this post


Link to post
Share on other sites

Regarding the font rendering: Do the GUIs of Doom support different textalignments? That would basically be a feature that needs to be integrated into XData-definitions as well.

Yes, Doom 3 supports textalignments, that's what I'm up to next.

 

By the way, I think the name RenderableFont was much more suitable for your class than RenderableText, as the latter suggests that we are dealing with an actual text here instead of a font. An XData-Object with render-support would rather be a RenderableText.

I'm not done yet - the RenderableText actually refers to the text string in the windowDef, and in my plans it's designed to compile the Shaders and the geometry needed to submit stuff to a RenderableCollector and subsequently to OpenGL. It'll take a few hours until I'm there, but you'll see it then. For each windowDef, a RenderableText object can be created to be used in the front-end render pass.

 

I also just had an idea for the two importer methods. As I said they currently return a copy of an XData-object respectively a list of XData-objects. Passing those as a reference would not only get rid of the copy-constructor-calls, but I could also make an exception-free implementation then by returning a bool and appending the import-breaking errormessage to the errormessagelist. I leave it up to you. Would you rather like to catch an exception or have a boolean returned?

I'm open to everything, as long as the behaviour of that method is documented in the header, I don't have a problem with either way. I still haven't looked in-depth into your setup so far, so I'm not really informed enough. :) Too little time between Alex, work and my other hobbies.

Share this post


Link to post
Share on other sites

I think I read somewhere that exceptions generally cost more performance and since this is my only current coding task, I guess I'll try to deliver a highly optimized product. :)

 

But what I was going at with the text-alignments was that currently they can't be specified within the XData-definition as far as I know. So my suggestion is that we should maybe try to integrate that feature into XData. (Could be my next task after the XData classes are done for the moment)

 

And I just had another idea. The list of XData-objects should preferably be sorted by Definition-name. So how would I go about implementing that? My first guess is using a std::set with a custom weak ordering criterion (don't know yet how to achieve that). The set.find() method should then also take the definition name as an argument for the search (don't know howto either).

 

/* Edit: I'd probably have to use a std::map for find() to work with the definition-name as a parameter, but storing this redundant information is not very clean... */

 

I noticed that you added a newline at the end of the XData loader, because of the compiler warnings. Can I enable those warnings somehow in VS 2008 too?

Share this post


Link to post
Share on other sites

I think I read somewhere that exceptions generally cost more performance and since this is my only current coding task, I guess I'll try to deliver a highly optimized product. :)

I wouldn't worry much about that tiny bit of performance. There are lots of other places where CPU cycles are lost so adding exception-unrolling code will hardly be noticeable. But I'm happy to see some hard numbers about the actual impact, I doubt it's measurable in units larger than µsecs. :)

 

But what I was going at with the text-alignments was that currently they can't be specified within the XData-definition as far as I know. So my suggestion is that we should maybe try to integrate that feature into XData. (Could be my next task after the XData classes are done for the moment)

Keep in mind that the textalign parameter is something you cannot change during runtime, it's only interpreted at GUI loading time, so you can't tell the GUI to switch alignments by the time the readable script is pushing the xdata contents to the GUI. I'm afraid this is something that needs to be handled by changing the GUIs themselves.

 

And I just had another idea. The list of XData-objects should preferably be sorted by Definition-name. So how would I go about implementing that? My first guess is using a std::set with a custom weak ordering criterion (don't know yet how to achieve that). The set.find() method should then also take the definition name as an argument for the search (don't know howto either).

 

/* Edit: I'd probably have to use a std::map for find() to work with the definition-name as a parameter, but storing this redundant information is not very clean... */

Yes, a std::map is what you need. All the other declaration managers in DarkRadiant work the same way (ShaderLibrary, ParticleManager, SoundManager, etc.). Each of them is mapping a std::string to the actual object.

 

Whether or not it's worth saving the duplicate std::string is debatable, but if you don't like it being stored twice, just remove the name string from the XData object and let the XDataManager take care of finding named objects. The XData object itself then is agnostic of its own name and only holds the xdata contents.

 

I noticed that you added a newline at the end of the XData loader, because of the compiler warnings. Can I enable those warnings somehow in VS 2008 too?

Nope, don't think so. It's not a big deal anyway, I just noticed it while skimming the file. Next time I'm havig a Linux development session I'll be running into that warning anyway.

Share this post


Link to post
Share on other sites

The next step is complete, DarkRadiant can now render text to the GUI display window, with support for word-wrapping, textscale, colours and textalign:

 

readable_dr.png readable_d3.png

 

The left screenie is from DarkRadiant, the right one is rendered by D3.

 

There are some issues left, as the nancy font is not rendered at the correct location and the D3 renderer is able to render smoother fonts.

Share this post


Link to post
Share on other sites

Hehe cool. The only difference I see is some vertical line-displacement and missing filtering. But the latter is not important at all. Good work!

 

Keep in mind that the textalign parameter is something you cannot change during runtime, it's only interpreted at GUI loading time, so you can't tell the GUI to switch alignments by the time the readable script is pushing the xdata contents to the GUI. I'm afraid this is something that needs to be handled by changing the GUIs themselves.

Ah, ok. I was assuming that the XData definitions were somewhat parsed into the gui definitions. The texts defined there somehow gotta get into the GUIs, I thought, resulting in my conclusion that a statement for text-alignment could be integrated as well. But well, it's not that much of an important feature and we can't adjust the text-alignment on a per-line-level anyway.

 

I wouldn't worry much about that tiny bit of performance. There are lots of other places where CPU cycles are lost so adding exception-unrolling code will hardly be noticeable. But I'm happy to see some hard numbers about the actual impact, I doubt it's measurable in units larger than µsecs. :)

Sure one exception less to handle makes up for nothing, but it's all the little optimizations that add up to a good product!! ;)

Share this post


Link to post
Share on other sites

Wow, this is really exciting. A wysiwyg readables editor would have a major impact on mappers. :)

Share this post


Link to post
Share on other sites

Ok, I think I've figured it out in the meantime, the font rendering is now pretty correct, almost pixel-perfect. The filtering issue is resolved as well, this was a general issue with DDS files:

 

readable_editor_dr.png readable_editor_d3.png

 

Left is DarkRadiant, right is Doom 3.

Share this post


Link to post
Share on other sites

Oh yeah, filtering is perfect now!! Looks exactly the same. Now there's still a small negligible horizontal offset in some parts and you forgot to render the fps-overlay!!!!!! :laugh:

 

Ah, on a closer look, I noticed that your renderer renders the 'o' actually better than Doom 3. :D But that character seems to be the only one that differs from the renderoutput of Doom, which I find a little weird...

Share this post


Link to post
Share on other sites

Since you're currently working on the readable editor GUI now, here are a couple of thoughts/ideas to consider:

-If the user selected to create a twosided readable, only twosided guis should be listed.

-Warn the user if he writes a glyph which is not available. (no texture coords)

-When exporting, suggest to use the name of the readable as filename.

-The user needs feedback. We either have to setup a couple of message dialogs or a console output. The latter is of course already available in the globaloutputstream, but who looks into that? :)

Share this post


Link to post
Share on other sites

I'm planning to create the rough outline of that editor, and - provided you are motivated - let you flesh out some details. Is that ok for you?

 

I'm going to brief you about what I've created up to that point and how I think the system should work, but I need to overcome a few technical hurdles first.

Share this post


Link to post
Share on other sites

Sure it's ok for me. I am actually glad I can still help a little... :) Those other tasks would probably have been a little over my head too. It would have taken me a hell of a lot more time than you.

Share this post


Link to post
Share on other sites
Sure one exception less to handle makes up for nothing, but it's all the little optimizations that add up to a good product!! ;)

 

Premature optimisation is the root of all evil. Clear, readable code is far more important than shaving a few milliseconds off some non-performance critical process.

Share this post


Link to post
Share on other sites

Nice going. This is looking great. :wub:

 

Dunno if relevant but since you're working at this low level maybe you can answer the question as to why world gui text is not rendered in our fast ambient mode so you just see a blank sheet or book unless you put a tiny ambient light on it.

Share this post


Link to post
Share on other sites

That is sweet. I didn't think we'd be seeing this feature any time soon!

 

I got a kick out of loading both images as textures into GIMP and setting the top one to Difference mode. The white text near the bottom is off by one or two horizontal pixels; but other than that, and some minor blemishes which are not visible to the unaided eye in the originals, it's perfect. Wow.

 

@Fidcal: Fast ambient just does a blend add of the diffuse texture, multiplied by the ambient level that's been set in code via the global material params (as you can see by opening any TDM material file in a text editor). World GUIs aren't part of the texture that's getting added, so they're ignorant of fast ambient and thus need actual light in order to show up. This is probably something that would need fixing in the closed-source renderer, unless there's a way to do something similar to a blend add on world GUIs.

 

The actual readable GUIs (the ones that come up when you frob) aren't affected because non-world GUIs are rendered fullbright, i.e. lighting doesn't apply to them.


My games | Public Service Announcement: TDM is not set in the Thief universe. The city in which it takes place is not the City from Thief. The player character is not called Garrett. Any person who contradicts these facts will be subjected to disapproving stares.

Share this post


Link to post
Share on other sites

XData import and export is finally completed with all necessary features (I hope so at least). Had to rewrite the importer quite a bit to make recursive importing possible, but it's all setup now and it can also deal with duplicated XData definitions.

 

How were you planning the preview renderer to be used by the way, greebo? Do you think it could be optimized in fashion that it could be updated while the user is typing? Thinking further: Use the preview window as the actual text-edit-field? :)

 

Premature optimisation is the root of all evil. Clear, readable code is far more important than shaving a few milliseconds off some non-performance critical process.

Yeah, that's probably right. But it's still very readable I think, so no worries.

 

That is sweet. I didn't think we'd be seeing this feature any time soon!

You guys should have invited me earlier to be a contributor... :P But well, basically I was just the one who pushed this forward and Greebo did all the hard tasks!! :)

Share this post


Link to post
Share on other sites

How were you planning the preview renderer to be used by the way, greebo?

The class layout is in my head, but I think I can draw it down somewhere to explain if you're interested. Basically, the GuiView is designed to be packed into any parent container. This can be a file preview window or the readable editor, every dialog needing to display GUI elements is entitled to instantiate a GuiView and pack it as child widget.

 

As for the readable editor itself, I have these rough plans in my head so far: It is centered around the readable Entity in the map which needs to be selected to fire up the editor, just like the stim/response editor. The editor is able to read the spawnargs from the entity, display the GUI, enables text-editing and is able to save back the spawnarg to the selected entity and to the xdata. It needs to support two usage schemes: creating a new readable and editing an existing one.

 

The workflow for creating a new one: the mapper creates a readable entity of his choice and opens up the readable editor dialog. The first thing is to define the inv_name (which is displayed in the HUD) and the xdata name (with an auto-suggestion: "readables/gathers/"). Multi-page editing must be supported, the first page is already created and the mapper can browse the available GUIs for it, the preview adapts itself accordingly. Once the GUI is selected, the editor presents a few text-entry boxes on the lower left (this is dynamically handled as the number and names of text entry fields depend on the selected GUI). During typing the text into the widgets, the GUI is automatically updated (this is the tricky part, as the readables are doing this with onTime GUI scripts, but I have some plans ready for this part too). When creating new pages, the GUI is "inherited" by default, but the mapper can override to have a different GUI for the different pages. On "Save", the xdata is created in memory and written to the map .xdata file, the spawnargs are saved to the entity. On "Cancel", nothing happens and no changes are applied to entity or xdata.

 

The workflow for editing is similar, the only hard part is to let the editor pre-populate all the widgets with the information found in the xdata.

 

Wanna have a go at it? I've been thinking about shifting my priorities and looking into the packaging scripts for the next release - this is an either-or situation, I can only work on one thing at once at this time.

 

Do you think it could be optimized in fashion that it could be updated while the user is typing?

I specifically designed the GuiWindowDef to allow real-time updates of the text, and apart from minor technical hurdles we're almost there.

 

Thinking further: Use the preview window as the actual text-edit-field?

This is a long-term goal - it requires a small selection system to be written which can translate mouse clicks into GUI space and requires quite some setup. Plus there are some potential issues with overlapping windowDefs, so this needs to be properly addressed, similar as I did back when I wrote the Texture Tool. For now, a set of simple GTK (multi-line) entry widgets will do the trick for mappers, as long as the preview is showing what's up.

Share this post


Link to post
Share on other sites

Just want to say guys, this is brilliant!!! :) Excellent work. Seriously. When you look at the tools Thief mappers work with now, DR is just what the doctor ordered. Whenever this readable editor is incorporated into a release, I think the community is going to drool and short out their computers. :)

Share this post


Link to post
Share on other sites

I actually rather dislike the approach that you have to select a readable in order to fire up the editor, because I also intended to make the live of pure translators like 7upman easier. They'd have to load the map (which depending on the mapsize can take years :laugh: ), search for the proper readables and start the readable-editor. It'd be much cooler for them to just launch DR and start the readable editor from the view-menu to open the desired readables. Allowing multiple instances of it would be the cherry on top, because they'd see the original text properly rendered as well. But that's not that neccessary as they can just start a second instance of DR.

 

This doesn't mean we shouldn't implement both ways though. Your approach surely offers more comfort to mappers.

 

I can surely take over the task now. I mean I still gotta learn for my exams, so I won't work by far as fast as you do (also due to my little coding experience), but the update definitely has the highest priority currently!! I hope you have a couple of comments like class descriptions in your current code. A brief overview would be nice either way or maybe even a small chatsession if our timezones match up somehwere... Where do you life by the way? :) I am GMT+1 (Germany),

Share this post


Link to post
Share on other sites

I suppose a crude way of doing that would be to have a tiny map with one readable. Open the target large map in a text editor. Search down for xdata_contents. Copy and paste it into entity inspector. Edit and repeat. Probably quicker than searching for the readable entities anyway in the original map in DR.

Share this post


Link to post
Share on other sites

You and your dirty hacks!! ;) We are in the initial design phase here, so I guess we should take as many usability aspects into consideration as possible.

Share this post


Link to post
Share on other sites

As translations happen far less frequent than mappers editing the actual readables, the priority of the readable editor should be the latter - of course, if we can make life easier for translators, that's cool, but definitely not at the expend of mappers.

 

Not selecting an entity when the editor is started is making things one level more complicated, as there needs to be a way to list all readable entities in the map - this is possible, the Objectives Editor is doing the same. Provided that mappers are not going to use the readable editor to create new readables (which poses the problem of where in the map the item should be created) this should be feasible.

 

For translators we might even provide a better method. If they just create a small add-on PK4 (e.g. patently_dangerous_fr.pk4 for a french translation package) which contains an additional xdata file instead of replacing the original one in the mission PK4, I can add a few code-lines to the TDM readable script such that it tries to load the xdata in the correct language. Like this:

 

Mapper creates:

readable1 referring to readables/patently_dangerous/english/secret_notice

readable2 referring to readables/patently_dangerous/english/secret_notice02

patently_dangerous.xd will be packed into patently_dangerous.pk4

 

Translators create:

An xdata file with readables/patently_dangerous/french/secret_notice and readables/patently_dangerous/french/secret_notice02

Pack this into patently_dangerous_fr.pk4.

 

TDM Readable code checks the sys_lang CVAR and attempts to load the readable of the preferred language, but falls back to the default if a language xdata is not available.

Share this post


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.

Sign in to follow this  

×
×
  • Create New...