Jump to content
The Dark Mod Forums

Visportals vs func_portals vs antiportals


SteveL

Recommended Posts

As this appears to work better the closer the occluder is to your eye, I wonder if it would be worth adding a check in the LOD system to enable attached occluders for the closest LOD entity.

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

As this appears to work better the closer the occluder is to your eye, I wonder if it would be worth adding a check in the LOD system to enable attached occluders for the closest LOD entity.

If it does, we'll have to look again at automatic occlusion! Easy enough to try by binding one to an AI and giving it a lod hide distance spawnarg of its own.

 

Two sides vs one sided

My suggestion is to default to two sided and have a spawnarg to make it one sided for those who want to fiddle with the setup. And in DR, it should be a brush that you shape then right-click > create entity. That'll make sure the mapper uses a 2d flat convex shape, without those rules having to be spelt out.

 

I guess it'll need a special texture like VPs to say which face is the occluder, unless someone can think of a simpler setup?

 

I should get as far as a performance test tonight. Last night I left it with a crowd of ai correctly having their models culled, but their shadows were still present and scratching their knees and picking their noses etc, as a result of stages 2 and 3 of the rendering process (the shadow fix) mentioned above. So their animations were still running every frame and detailed shadows being painted and I didn't see fps improvement. But I've worked out what I need to do to fix that. Just need to figure out the cheapest test for whether a shadow could be in view.

 

The cheap-ish test the renderer uses right now is to take the bounding box of the entity, plus the origin of the shadowcasting light that hits it, and calculate the 3d shadow volume of the bounding box, protecting out into space. Then it cuts down that volume to just the part that's in the light volume. Then it tests whether any part of the remaining shape is in view.

 

That's a fairly expensive process. Small compared with some of the other rendering operations, but weighty enough that it only bothers with the check for animated meshes like ai. It skips it for FS and lets them be drawn regardless, because they don't move and can use their cached shadow from the previous frame (though that shortcut would backfire in the presence of a moving light). And it wouldn't work for my preferred outdoor setup, a massive "ambient" parallel moonlight, because the clipped shadow vols would extend well below the floor and never get occluded. That's not a deal breaker though: I've spotted at least 2 places where I think the front end is not properly handling parallel lights, so I've raised a tracker to work on it later.

 

So I can either find a cheaper test, or I can cut down the number of entities that get tested by doing it only for entities that got occluded in the previous pass.

Link to comment
Share on other sites

@grayman, if you're still monitoring this thread could you offer any advice please or at least have a think about how the game code (not the renderer) can detect that an occluder has moved? Preferably without adding a Think() method to occluders as the vast majority will be stationary, so that'd be wasteful. Is there a central function that always gets called whenever something moves? I'm hopeful you'll know because I saw the work you did to ensure that Lights get their On() and Off() methods called no matter how they get switched on or off or faded out. I'm hoping there'll be a similar regular thing for movers.

 

The renderer can't check on an in-game entity directly. The game entity will have to set a flag or something similar, for the renderer to know. Like entities at the moment set flags through their renderEntity pointer.

Link to comment
Share on other sites

If it does, we'll have to look again at automatic occlusion! Easy enough to try by binding one to an AI and giving it a lod hide distance spawnarg of its own.

 

One performance optimization would also to discard occluders that are too small on the screen (maybe on how far away the are?) If the occluder only covers a small space, it cannot occlude much.

 

But it is hard to say wether the occluder test will be cheap enough to not care for that. Better first get the implementation 100% working, then worry about special cases :)

 

About "binding": If the occluder is just a special texture flag or type (like a shadow texture), then you could add a second material to an AI with the occluder texture. This could then be changed like a skin. Not sure if this is more complicated than having a small rectangular (or oddly shaped) flat plane stuck inside the AI.

 

If you got for a brush with the occluder texture, there would be no way to manipulate them from scripts, or with LOD, wouldn't it? Unless you make them an entity. (visportals are no entities, f.i.) Or do I confuse things here?

 

Two sides vs one sided

My suggestion is to default to two sided and have a spawnarg to make it one sided for those who want to fiddle with the setup. And in DR, it should be a brush that you shape then right-click > create entity. That'll make sure the mapper uses a 2d flat convex shape, without those rules having to be spelt out.

 

I guess it'll need a special texture like VPs to say which face is the occluder, unless someone can think of a simpler setup?

 

I think the special texture is the simplest setup, it is already used in a lot of places, so people understand it. Also, you can filter out occluders in DR with a rule like visportals, so this sounds the easiest way.

Edited by Tels

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

Link to comment
Share on other sites

Must admit I'm wondering whether binding and so forth would ever get used for occluders. Would anyone really build a scene that only performs well if the player has someone standing in front of him or is holding a crate? Or am I thinking too small again? But enabling it is pretty much free, because we'd need them to be entities anyway. (Making them worldspawn would be far too much trouble. Probably it would mean changing dmap and the proc file.)

 

I've only skimmed this thread, so I'm not caught up on the renderer details. Don't you have to use an occluder's current boundary and orientation each frame anyway? Why would you need to know when movement has occurred?

 

The renderer won’t be able to call any functions on the occluder to find out where it is. It’ll need the occluder to post it any changes. Entities do the same thing through their renderEntity pointer, and lights do it through their renderLight pointer. Those pointers lead to structs in the renderer’s allocated memory, and they’re how the game notifies current state. For its own part, the renderer appears to have no awareness of the game whatsoever. It just has some memory banks that are updated by something outside itself, and it gets to work on what it finds there.

 

Sometimes a pointer to the renderer is the entity's only place that it keeps a piece of info, so it's not obvious what's going on. I had that problem when working with the LOD AI jerking bug. I wish I'd done this renderer deep-dive first, would have saved me a lot of puzzling :)

 

In the case of an occluder, it’ll only need to notify its current list of point coordinates and whether it’s 1- or 2-sided, and only if something has changed. I was wondering if there’s a way to achieve that without having every occluder Think() every frame to see whether it’s been moved. Scripts might be easy to handle because we can override the script events and update the renderer’s info there, if there’s no central function that always gets called. But I’ve no idea how entity origins get updated when they’re bound to something, or whether there’s a way to selectively run Think() just when something is on the move. Hmm, other bound entities must be posting their new origin and axis every frame … We’d need it to post a winding too (unless we decide that scripts aren’t allowed to change that).

 

One performance optimization would also to discard occluders that are too small on the screen (maybe on how far away the are?) If the occluder only covers a small space, it cannot occlude much. But it is hard to say wether the occluder test will be cheap enough to not care for that. Better first get the implementation 100% working, then worry about special cases :) About "binding": If the occluder is just a special texture flag or type (like a shadow texture), then you could add a second material to an AI with the occluder texture. This could then be changed like a skin. Not sure if this is more complicated than having a small rectangular (or oddly shaped) flat plane stuck inside the AI. If you got for a brush with the occluder texture, there would be no way to manipulate them from scripts, or with LOD, wouldn't it? Unless you make them an entity. (visportals are no entities, f.i.) Or do I confuse things here? I think the special texture is the simplest setup, it is already used in a lot of places, so people understand it. Also, you can filter out occluders in DR with a rule like visportals, so this sounds the easiest way.

 

They'll be entities. It's probably a good idea to ignore distant or small occluders like you say, plus those that are almost side-on. As for AI, well the occluder has to be a simple convex shape or the tests *would* get expensive.

 

I'm first going to find out whether or not big, square occluders taking up half the screen offer noticeable benefits before considering little moving ones :) I feel a bit sheepish stirring up all this conversation before I've got that demonstrated!

Link to comment
Share on other sites

Must admit I'm wondering whether binding and so forth would ever get used for occluders. Would anyone really build a scene that only performs well if the player has someone standing in front of him or is holding a crate? Or am I thinking too small again? But enabling it is pretty much free, because we'd need them to be entities anyway. (Making them worldspawn would be far too much trouble. Probably it would mean changing dmap and the proc file.)

 

You are right, if the performance is only good if you are holding a crate in front of you, the map is designed wrong :D

 

As for entities, oh, yeah, I had the idea they would be worldspawn like visportals. If they are entities, then this has some benefits, but also drawbacks.

 

The number of entities is quite limited, and an entity is quite a "heavy" struct just to hold a few coordinates. Having thousand of occluders is out of the question this way (esp. if you want Think() being called every frame :)

 

OTOH, each occluder must be its own entity with its own name and so on, otherwise you cannot manipulate them with scrips.

 

There are two ways you can deal with the entities:

 

* just let them be entities (easy, nice for proof-of-concept)

* internally, let the engine manage them. Then you need script functions to * add an occluder, query occluders and manipulate (at least move and resize) them

 

In the second case you cannot bind them to anything, tho.

 

So entities are far easier to manipulate, but they also have quite a heavy cost (even if the entity is just "empty"). It's ok for a few hundred, though.

 

As for the Think(): Usually the engine makes it so that things are statics, unless you move them around. E.g. the occluders would not think() (because they don't move), but if they are bound to something, they will be moved around by the bind master. Also, scripts generally move things around by simply calling "setOrigin()", even for the player. (You can look at the teleport routines)

 

So if you post the updates to the renderer whenever "setOrigin()" is called, it should be fine.

 

Also, occluders would not need a physics object as they don't move on their own, or are moveable.

 

The renderer won’t be able to call any functions on the occluder to find out where it is. It’ll need the occluder to post it any changes. Entities do the same thing through their renderEntity pointer, and lights do it through their renderLight pointer. Those pointers lead to structs in the renderer’s allocated memory, and they’re how the game notifies current state. For its own part, the renderer appears to have no awareness of the game whatsoever. It just has some memory banks that are updated by something outside itself, and it gets to work on what it finds there.

 

Sometimes a pointer to the renderer is the entity's only place that it keeps a piece of info, so it's not obvious what's going on. I had that problem when working with the LOD AI jerking bug. I wish I'd done this renderer deep-dive first, would have saved me a lot of puzzling :)

 

In the case of an occluder, it’ll only need to notify its current list of point coordinates and whether it’s 1- or 2-sided, and only if something has changed. I was wondering if there’s a way to achieve that without having every occluder Think() every frame to see whether it’s been moved. Scripts might be easy to handle because we can override the script events and update the renderer’s info there, if there’s no central function that always gets called. But I’ve no idea how entity origins get updated when they’re bound to something, or whether there’s a way to selectively run Think() just when something is on the move. Hmm, other bound entities must be posting their new origin and axis every frame … We’d need it to post a winding too (unless we decide that scripts aren’t allowed to change that).

 

Entities have setOrigin() and I do think they simple notify the renderer of every change. Bound entites are a difficult beast in the engine, one entity is the master, and all others are children. The children have their origin relatively to the master, every time a master changes, all the children are moved with it. The children are basically glued on.

 

(Bound entity groups have a lot of problems in the physics engine, because impulses are sometimes not transfered good between them, and also, the bind points are static and not flexible etc. But I digres :).

 

They'll be entities. It's probably a good idea to ignore distant or small occluders like you say, plus those that are almost side-on. As for AI, well the occluder has to be a simple convex shape or the tests *would* get expensive.

 

I though of occluders are rectangular shapes. Or at most a few triangles. Basically, a single convex polygon.

 

I'm first going to find out whether or not big, square occluders taking up half the screen offer noticeable benefits before considering little moving ones :) I feel a bit sheepish stirring up all this conversation before I've got that demonstrated!

 

No no, the conversation was very inspiring and we all learnt a lot :) But the idea with a benchmark is probably a good one :)

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

Link to comment
Share on other sites

I have optimism for this feature.

 

I think Carmack was very conservative with culling in general so that reflections and off-screen shadowcasters would not be messed with.

It also allowed him to quickly drop-in a ray-tracing renderer for testing purposes. While it's great for forward-looking features like ray-tracing,

it's wasteful to render what we're currently rendering AFAIK (especially since Hierarchical-Z generally doesn't work with vanilla Id Tech 4).

Preventing more triangles from hitting the backend this way is one step closer to a deferred renderer in terms of overdraw prevention.

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

As for entities, oh, yeah, I had the idea they would be worldspawn like visportals. If they are entities, then this has some benefits, but also drawbacks.

 

The number of entities is quite limited, and an entity is quite a "heavy" struct just to hold a few coordinates. Having thousand of occluders is out of the question this way (esp. if you want Think() being called every frame :)

 

OTOH, each occluder must be its own entity with its own name and so on, otherwise you cannot manipulate them with scrips.

 

There are two ways you can deal with the entities:

 

* just let them be entities (easy, nice for proof-of-concept)

* internally, let the engine manage them. Then you need script functions to * add an occluder, query occluders and manipulate (at least move and resize) them

 

In the second case you cannot bind them to anything, tho.

 

Thanks, I hadn't thought of that alternative. One entity to cover all occluders. How would that be implemented? Can an entity register its coordinates with The One True Occluder while it's spawning then Remove() itself immediately?

 

@nbohr1more: I'm optimistic too, hence all the midnight oil I'm burning. Who's Carmack? Is he the unknown "remarkably talented coder" whose work I was praising above, or the designer or something? I have no idea what hierarchical-Z might mean by the way so please keep an eye on what I'm doing :) I'll be sharing implementation details to garner suggestions just as soon as I get a POC build to show a clear FPS boost so we all know we've got something to work with.

Link to comment
Share on other sites

I wasn't joking ( :blush: ! ), but now you come to mention it I realise I've read a couple of his interviews including the one with Fabians Anglard re the engine design.

 

I'm not immersed in game design or developments at all. I'm a database coder with a nerdish hobby in algorithms who just happens to have got hooked on TDM and is enjoying learning new stuff. So I'll be sure to share a lot of detail in the forum so that you guys who do follow such stuff can put me right if I come up with an idea that everyone else abandoned years ago :)

Link to comment
Share on other sites

Hierarchical Z:

 

http://en.wikipedia.org/wiki/HyperZ

 

Deferred Rendering:

 

http://en.wikipedia.org/wiki/Deferred_shading

 

The folks over at beyond3d forums have obsessed over PowerVR and overdraw for ages so it's something I have a fair amount of background with

from a theory POV.

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

A mini update because I didn't get as far as perf testing last night. I'm back with geometry. I borrowed the "cheap-ish" code for testing whether any potential shadow was in the occluded zone, but it's not letting me cull shadows and therefore animation updates unless I'm standing right up against the occluder.

 

post-29566-0-75535400-1408518881_thumb.jpg

 

You can see in the pic that the projected shadow volume (white shape) does capture the AI and his shadow, but it extends well below the room which is why you have to stand right against the occluder (cyan) for the whole of it to be hidden. I used the idFrustum method "ConstrainToBox" to clip it to that size, but it seems to be very generous. The box in question is the bounds of the light volume which ends about 3 feet below the floor. Partly that'll be because a frustum needs its top and bottom to be parallel, whereas I could do with a more irregular shape. But even then it's allowing a lot of extra room in the frustum. It *is* doing some clipping by the way, else the frustum would go on right to the edge of world space. More sums tonight.

Link to comment
Share on other sites

Thanks, I hadn't thought of that alternative. One entity to cover all occluders. How would that be implemented? Can an entity register its coordinates with The One True Occluder while it's spawning then Remove() itself immediately?

 

Yes, certainly. For instance, the SEED system does things in this way, because of the entity limit. Swift Mazes does things (but in scripting) for similiar reasons. Everytime you want no to have a full entity around, but just want it easier to be setup in DR, you can use this trick.

 

[Edit: The place to use might be the Spawn() function of an entity. Look for the implementation of "random_remove", it inhibts the spawning of an entity by random chance, this might be want you want to follow)

 

However, not having the entity around means it cannot be easily manipulate at runtime and every manipulation people might want has to be added first.

 

For the first step I'd let them be entities - the other way is an optimization and we all know that Premature optimization ist the root if all evil™ :)

Edited by Tels
  • Like 1

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

Link to comment
Share on other sites

A mini update because I didn't get as far as perf testing last night. I'm back with geometry. I borrowed the "cheap-ish" code for testing whether any potential shadow was in the occluded zone, but it's not letting me cull shadows and therefore animation updates unless I'm standing right up against the occluder.

 

post-29566-0-75535400-1408518881_thumb.jpg

 

You can see in the pic that the projected shadow volume (white shape) does capture the AI and his shadow, but it extends well below the room which is why you have to stand right against the occluder (cyan) for the whole of it to be hidden. I used the idFrustum method "ConstrainToBox" to clip it to that size, but it seems to be very generous. The box in question is the bounds of the light volume which ends about 3 feet below the floor. Partly that'll be because a frustum needs its top and bottom to be parallel, whereas I could do with a more irregular shape. But even then it's allowing a lot of extra room in the frustum. It *is* doing some clipping by the way, else the frustum would go on right to the edge of world space. More sums tonight.

 

I'm note sure if the shadow is "unbounded" because it just extends really far away, or because it extens so far due to the light range. Hm, but even with a light with a very small range, I think the shadows always extend as far as they are. (e.g if you have a light with 100units radius, you will see no light beyond that range, but the shadow projected could well be 1000 units).

 

Looking forward to your tests.

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

Link to comment
Share on other sites

I should have made that post clearer. The white pyramid isn't the actual shadow volume, it's the occluder's guess at what the shadow volume will be. Unfortunately it's way too large, because the light volume has its floor only 24 doom units below the target's feet. That means it's screwing up -- I can't occlude the shadow volume and safely cull the animation and shadow updates because that extended volume sticks out of the bottom of my occluder unless I'm standing right by it.

 

I didn't invent the cheap prediction code for this test: I got it from another part of the renderer. I'm sure it'll be easily fixed, but it's a nuisance and the data being used is opaque to humans.

Link to comment
Share on other sites

Looking again at the picture, I think the guess might be actually correct. The shadow is only that small because of the floor - but the light doesn't "know" that. If the floor was some steep wedge, the shadow might be actually quite long and extend a large way down. I'm not sure how to solve this.

 

What happens if the AI and light are further away from the occluder, does that make it better?

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

Link to comment
Share on other sites

Looking again at the picture, I think the guess might be actually correct. The shadow is only that small because of the floor - but the light doesn't "know" that. If the floor was some steep wedge, the shadow might be actually quite long and extend a large way down.

No, it wouldn't, because the edge of the light volume is only 24 units below the AI's feet. Lights don't cast any light (and therefore shadow) outside of their volume, so it should be fixable by limiting the depth of the guessed volume.

 

What happens if the AI and light are further away from the occluder, does that make it better?

Kind of. But because the player and AI and occluder are all about the same level, I think you'd have to move it quite far to get that overestimate back in range of the occluder. I need to find an efficient way of clipping it more.

Link to comment
Share on other sites

No, it wouldn't, because the edge of the light volume is only 24 units below the AI's feet. Lights don't cast any light (and therefore shadow) outside of their volume, so it should be fixable by limiting the depth of the guessed volume.

 

Yeah, that was my question actually. Does the shadow stop hard at the light volume egde? Or does the renderer draw the shadow further out? (Oh boy, such simple questions I have to ask - it is like I never saw TDM before :D

 

Kind of. But because the player and AI and occluder are all about the same level, I think you'd have to move it quite far to get that overestimate back in range of the occluder. I need to find an efficient way of clipping it more.

 

Hm, yes, looks like otherwise shadow-casting objects would not be occluded in most cases.

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

Link to comment
Share on other sites

As far as I recall, the optimization to keep shadows bound to their light volume was only added in Doom 3 BFG, Vanilla still calculated shadows outside the volume?

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

Yep:

 

 

Unlike the original DOOM 3, nothing is done lazily anymore (except for generating animation frames, no more

flags and tests like: "calculate this right now if it has not been calculated yet"). All the high performance CPU

work now follows the streaming programming model. For dynamic shadow volumes the engine now culls

triangles to the light volume, both to reduce the number of shadow volume triangles and to reduce the number

of triangles that are redrawn for each light pass. The engine now also performs a precise test to determine whether the view intersects or is

inside a shadow volume.

 

This precise test is important to significantly reduce the number of cases where shadow volumes have to be rendered with Z-fail [1] because Z-fail rendering is

significantly slower on a various graphics hardware (in particular at high resolutions). For this precise inside test a line-versus-expanded-

triangle intersection test is performed for every single shadow volume near cap triangle where the linegoes from the view origin to the light origin.

 

The shadow volume is also transformed into clip space and the polygons are clipped to the view in homogeneous space to calculate very tight depth

bounds. In particular in the cases where shadow volumes do have to be rendered with Z-fail, the depth bounds are used to get more Z-Cull/Hi-Z benefit

(at least on the hardware that supports the depth bounds test).

 

Edited by nbohr1more

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

For dynamic shadow volumes the engine now culls

triangles to the light volume, both to reduce the number of shadow volume triangles and to reduce the number

of triangles that are redrawn for each light pass.

 

I'm trying to work out whether that has any implications for occlusion. The front end won't generate any interactions for surfaces outside a light volume, but a surface can be partly inside the volume of course and then it'll get interactions. You can't see a shadow outside its light volume, so even if the engine is doing extra work to "draw" it invisibly, occlusion shouldn't be able to make shadows "pop".

 

This AI has a light right next to him, and the floor is flat and square so it's only 2 tris. The light volume ends quite close to him, so you can see the visible light and shadow don't get (visibly) propagated across the entire triangle:

post-29566-0-66504200-1408606797_thumb.jpg

 

You can see why his shadow (and animations) don't get culled when he's close to the occluder. The pyramid proceeds from the light, and the volume between the intersecting plane and the base of the pyramid is the zone where he could feasibly cast shadows. It sticks out from the occluder a bit.

post-29566-0-79923400-1408606793_thumb.jpg

 

However, if as Tels suggested, we just move him a bit further back from the occluder, his shadow does vanish a lot more easily.

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

    • nbohr1more

      Was checking out old translation packs and decided to fire up TDM 1.07. Rightful Property with sub-20 FPS areas yay! ( same areas run at 180FPS with cranked eye candy on 2.12 )
      · 2 replies
    • taffernicus

      i am so euphoric to see new FMs keep coming out and I am keen to try it out in my leisure time, then suddenly my PC is spouting a couple of S.M.A.R.T errors...
      tbf i cannot afford myself to miss my network emulator image file&progress, important ebooks, hyper-v checkpoint & hyper-v export and the precious thief & TDM gamesaves. Don't fall yourself into & lay your hands on crappy SSD
       
      · 5 replies
    • OrbWeaver

      Does anyone actually use the Normalise button in the Surface inspector? Even after looking at the code I'm not quite sure what it's for.
      · 7 replies
    • Ansome

      Turns out my 15th anniversary mission idea has already been done once or twice before! I've been beaten to the punch once again, but I suppose that's to be expected when there's over 170 FMs out there, eh? I'm not complaining though, I love learning new tricks and taking inspiration from past FMs. Best of luck on your own fan missions!
      · 4 replies
    • The Black Arrow

      I wanna play Doom 3, but fhDoom has much better features than dhewm3, yet fhDoom is old, outdated and probably not supported. Damn!
      Makes me think that TDM engine for Doom 3 itself would actually be perfect.
      · 6 replies
×
×
  • Create New...