Jump to content

FeXoR

WFG Retired
  • Posts

    1.426
  • Joined

  • Last visited

  • Days Won

    28

Posts posted by FeXoR

  1. Can you give a "better" example of how triggers would be beneficial in the implementation of RMS? "Event: new game started, Condition: true (no condition), action: [all the random map code]" doesn't seem too mindblowing?

    I have not much time right now but I think about writing this map in trigger function (without writing the functions explicitly) just to show how it would look like (or how I think it should).

    I actually would like to see triggers in part 1 too, but mainly because it enables single-player missions - not for programmatic reasons.

    Thats another thing. It would enhance gameplay.

    I cannot say much about the specific programmatic reasons for why to do things one way or another, but I do think that regardless of whether or not the bulk of the engine will need to be rewritten in part 2 for triggers it will probably need to be rewritten more or less completely anyway to make it possible to make use of more than one CPU. Which kind of invalidates the "but you will have to rewrite everything" argument as the rewrite will be needed anyway, and that might actually be another reason to postpone the addition of triggers, better to add both things that require a rewrite at the same time as there's the need for two rewrites otherwise.

    There might still be other reasons that would make it worth adding triggers at this point, but I think that unless we decide to do something as major as that (at least if it's as major as you describe it with more or less a complete rewrite of parts of the engine) we're getting really close to the finished game.

    That's only true in part. To add trigger events to the engine those functions has only be added e.g. the damage calculation is done anyway. It just doesn't send the event to the triggers. But if the engine has to be rewritten to make parts of it threadable it would have to be rewritten on a larger scale.

    However. The code to be rewritten will be the code to write for triggers (that's fixed and mainly of an unknown amount) and the part we have to implement before they are added. The amount of the second depends on when they are added and how complete the game was before. So first finishing the game means RMGEN/AIs working quite well. So: The code will be more then if triggers where implemented earlier and everything was trigger based. And at first glance the need to change them to be trigger based vanishes. That hurts me!

    Not as in "we could release part one within a couple of months", but as in " we should decide now if we want to have a release out within one or two years or within four to five years". Each individual piece we add might not increase the development time immensely, but I think it's time to start evaluating things more strictly to see if they're worth increasing development time for. Otherwise we'll keep working forever on the "perfect game" and never reach it, it's better to be able to release a good game soon and then keep improving on it in subsequent releases.

    I fear you are right with this. It's important to have something finisched at some point and while implementing triggers might "only" take about 1 year making everything trigger based might take about the same amount of time or longer.

    (Perhaps the last few posts should be migrated to a separate topic?) I'm actually curious why triggers are considered a 'major' addition insofar that a trigger is just "something that calls something else on some condition". At first blush, that seems pretty straightforward compared to some other recent additions, like click-drag walls and the new sound manager. So what is the catch? :)

    I couldn't hold it (again) x)

    For one part I still fear that implementing triggers as widely as I think would make the difference between "another modifiable" and a "awesome easy to do mindblowing stuff with" game when not starting ASAP since RMS and AIs seam that well working that nothing seams to be gained by using triggers for them so they will only be used for story driven maps (And no triggers that for terrain manipulation or handling a player (AI) will be added). That's nothing really new. Some might argue similarly as you did: "Why should some part of the game have access to stuff they don't need?". Yes, in the common case it might seam to just be overhead. But in the end (when more and more users wright maps/scenarios/mods for it) the gain will be enormous. Especially if the changes are easy to do and all concepts can be implemented using only one part (Triggers/simulation). But that's to hard to do even for team members ATM so an AI-API and an RMGEN part was added.

    I fear feneur is right about the amount of time needed to do this.

    I'll try to shut up for a few (hopefully many) month about this.

  2. Awesome update Fexor :)

    On the other hand glas to see a bit of a debate going on :D

    BTW I created ticket 1634 specifically for that issue.

    Thx. I'll follow the tickets and am thinking about how to implement it for RMGEN.

    It's usually not considered good practice to arbitrarily allow one part of a program to modify other parts of the program, hence scopes.

    True. So it might be a good idea to use fixed prefixes for the general function in triggers and the more specific functions for RMS/AI e.g. te_blaBlub could be used for trigger events, tc_blaBlub for trigger conditions, ta_blaBlub for trigger actions, ai_blaBlub for more specific AI functions and rm_blaBlub for more specific functions for random map generation. I don't want to make the engine accessible directly BTW. The engine just calls the event checks when they happen and give more specific information about the event by setting the variables like "damagedUnit" to a copy of that unit and the trigger actions pass the changes to be done to the engine when they are valid.

    Why not just break the common stuff out into include files?

    I don't think that will work properly because stuff is made explicitly for that one part of the program e.g. in the RMGEN functions a "closed" wall can be build (which would be useful for the AI) but the placement is instantly (not the construction foundation is placed but the finished wall). Additionally rmgen uses an abstract "map" without the engine running. It is not designed to work during engine runtime and so will not work for AIs.

    The other way around: AIs have functionality for terrain analysis. This would help to restrict entity placement in RMGEN, too, but doesn't work with RMGENs abstract g_map.

    As the functions are now makes perfectly sense when not considering fusing those parts (which is quite hard anyway without triggers) and so we'll write more and more code to carve in stone that RMGEN/AI will never get trigger based and disable the vast possibilities arising with it.

    So adding triggers ASAP will lead to more usable, less redundant and extremely variable code while not doing it leading to vast amounts of duplicated later obsolete code OR (if not fusing AI/RMGEN/simulations trigger based) a much less spectacular/modifiable/usable end product.

  3. What is the advantage of AIs having access to the RMGEN stuff?

    It is not the advantage of AIs having RMGEN stuff but the advantage is there is no RMGEN stuff and AI stuff any more. There are just general functions to manipulate "everything" (with triggers, that take care of things are done same and pass it to the engine if needed/valid). So terrain can be manipulated in the "first turn" to generate random maps and everything has access to all information (so it would be much simpler to avoid many problems in RMGEN we have to fight with e.g. no access to entity templates). In general the advantages are far beyond anything that can be predicted. The vast amount of possibilities arising by it is just mind blowing. AIs would extremely profit from it as well, since they, too, would have all information and so can more sensible take actions.

    Another example that would help both - RMGEN and AI - is a terrain analysis for areas passable/reachable/buildable. There are many more but I already talked about that until I got blue in my face:

    http://www.wildfireg...showtopic=16096 A thread about this...

    http://trac.wildfire...1449#comment:20 Scip untill "The perfect world:"...

    And we need it anyway to build a story based campaign (yes I know it is planned for part II).

    Isn't RMGEN filled with functions for terrain manipulation and other stuff that no player (whether human or AI) should have access to?

    In the first place: Why shouldn't they???

    Or more calm: Information about if a part of the maps can be passed/build upon/reached is needed for both.

    Can't the AIs build walls with the usual AI API?

    Yes... if you like implementing redundant stuff over and over again for every part of the game not connected. (ATM there's an in-game method and a tool for RMGEN only AFAIK).

  4. How would you use triggers in RMS? (Not saying that you shouldn't, just trying to find out what exactly people understand by 'triggers'.)

    "Triggers" are functions that can manipulate something during runtime of the engine.

    A trigger usually is made of:

    - An event: when it is triggered.

    Example:

    aUnitTookDamage

    (while that event is triggered once for every damage calculation and with it sets some "global variables" like e.g. "damagedUnit" (and/or "triggeringUnit"), "damagingUnit", "dealedDamage" and "lostHealth" in this case)

    - Conditions: in which case the actions should be called to minimize overhead.

    Example:

    damagedUnit.type == "athen_infantry_spearman"

    damagedUnit.level >= 2

    damagedUnit.health < damagingUnit.health

    - Actions: Mainly code that calls several functions that does something with the engine.

    Example:

    playSound("allert_01", positionOf(damagedUnit))

    pingMinimap(positionOf(damagingUnit)))

    messageToPlayer("An advanced spearman is about to loose", ownerOf(damagedUnit))

    If you implement all actions possible you can do everything with triggers. Because it's possible to use them during game time you can do awesome stuff. But for now a (very rough) concept of how to do a random map with it: Event: new game started, Condition: true (no condition), action: [all the random map code]. For that mainly all the functions in RMGEN libs has to be reimplemented as triggers. But that way not only RMGEN can use them, but e.g. the AIs too (to build walls for example). AIs ATM are "loosely" connected to the engine to ensure threading the AIs will indeed make sense. So many of the trigger actions should be thread save and can be used on the actual map the engine works with or on a threaded representation of it. That way AIs could have full access to all map data and still run on another CPU. ATM simulation is mainly the part that comes closest to triggers so this would be the place to start implementing triggers.

  5. I think the thing is that terrain flattening should be smooth and affect the area around it and not just below the building. I think there are three parts to good building placement: restrictions (if the ground is too uneven it won't work well even if the ground is flattened underneath the building - the difference to the surrounding area would be too large and cause "pits" etc where the building is), foundations for the buildings to make them possible to place even on slightly uneven terrain, and smooth terrain flattening to make it work on slightly uneven terrain :)

    I totally agree. But ist the same old problem that makes it hard to realize in RMGEN: No access to the templates...

    Otherwise I'd done it already...

    Another thing: It will not work well on a "huge ramp". Whatever you do when flattening the ground under/around the building it will make the total ground on the ramp more uneven.

    Some buildings have foundations that would work fine with ground that isn't flattened completely (except some of the props like barrels which are supposed to sit on the ground), but since there are also buildings that wouldn't work well with bumpy terrain, there would have to be something (in the buildings' templates, maybe) to tell the engine which buildings need flat terrain.

    This does not work for RMGEN...

    Just to go on your nerves again: I'd really like to make everything (especially simulations, RMGEN and AI) trigger based and generate RMS while the engine runs. Don't wait until part II. It will really be more work in the end NOT to add trigger due to tons of duplicated code. Not to mention all the time spend to think about workarounds for things not well doable without full access.

  6. I don't think anything but completely flat will work, because some buildings (like the Greek civil center) have floors (or tiles in the case of the Greek civil center) that wouldn't look good if the ground underneath isn't completely flat.

    Oh, true. BTW I like the tiling style of the Greek Civil Centre. I still think buildings in general should reach a bit further into the ground.

    Terrain flattening works just fine in AOE3 or AOM.

    I'm quite sure it can work well and agree that it would improve things, yes.

    Late EDIT: I changed my mind : http://trac.wildfiregames.com/ticket/21#comment:10

  7. Why not start with the player positions defined, and use that as a constraint when generating the terrain? Otherwise you end up with situations where there may be no room to place a player, especially on smaller maps or when there's many players, and as you say the random(?) search for valid positions is time-consuming.

    I could do this and place the terrain after the players and restrict placement of other entities in the areas around the players but:this is mainly a test of concept map for heightmaps generated by erosion to look more natural. To derivate players like I do now feels more natural to me as well. Additionally there's no way to tell if the predefined start locations will be placed where water shows up on the random terrain (Or after everything is build and a player is detected in water the heightmap would have to be rebuild... even more time consuming OR the heightmap would have to be changed "artificially" afterwards to ensure the players are placed valid which somehow defeats the purpose of this map). Most other maps (or all) are done like you suggest but I think variety in the random maps is a good thing, not only in design but also in the general approach. In some rare cases it can indeed happen that there are not even 8 valid start locations but only on a tiny map. I'm pretty sure that no one would like to play with 8 players on a tiny map and many other RMS will wind up in chaos as well with this settings

    EDIT: The players start locations are chosen "randomly" because lets say there are 100 valid tiles found to place the start positions and there are 8 players present leading to a number of 100^8 = 10^16 = 10000000000000000 possible player derivations. Looping over them will result in an out of memory error. So I randomly pick 10000 possible derivations and finaly take the one with the maximum player distance (more precise the derivation with the maximum distance between the 2 players closest to each other).

    Now all we need is buildings flattening terrain when being constructed. :)

    That would help, yes. Keep in mind though that flattening the terrain in one area will make it more step on the edges of that area so it might be good not to flatten it totally but only make it more flat. The changes to the terrain will be seen after the building is destroyed as well and might look a bit strange but it's quite realistic that terrain build by mankind looks a bit "unnatural". another question is: Will it be applied to buildings placed in random maps at all? I guess it will have to be implemented for RMGEN separately...

  8. Here's another version.

    Changes:

    - Players will not be placed in the corners (only inside a circle fitting into the rectangular map)

    - Players will now be close to "bog" (low ground) and "woods" (high ground) so they will more likely have access to all resource types (due to the very random nature of this map an equal amount can still not be ensured).

    - Again added more bushes to the "bog".

    - Reduced the number of deer entities.

    - Very Large and Giant maps does not seam to raise an out of memory error any more (not sure why, guess the extreme reduction of possible start positions is the reason).

    The map takes longer to generate now because of the "ensure players are close to low and high ground" check.

    In some cases the added start location restrictions result in less "equal" start location derivations over the map. I still think it's an improvement. Here's a screen shot that shows that:

    post-14196-0-82524700-1347971096_thumb.j

    Since no high ground is top left no player is placed there. So one player is more in the mid of the map so more likely to be attacked. That does not happen often with 3-5 players. With more then 5 players it's natural (when maximizing distance between players) and intended.

    And the map: belgian_uplands2012-9-18.zip

    If no further bugs/objections show up I will add a ticket soon to add this map after I cleaned up the code.

    Afterwards I will refocus on a general erosion lib for rmgen and mess around with the existing maps :tease:

  9. Don't know if you are already aware of this, but sometimes walls are generated which exceed territory boundaries, which apparently causes them to gradually lose health and eventually die:

    This happens because some wall parts are outside the map while the territory border can't expand over the map border. I could add restrictions not to place wall entities outside the map.

    The better way to deal with that would IMO be a check in each random map for the size of the map and dependent on that and how close the player start locations can be to the border the map designer should disable Iberian walls (e.g. by placing them with "placeCivDefaultEntities(x, y, playerID, BUILDING_ANGlE, {'iberWall' : false});"). I just can't know well what the map designer wants/ how much space each map grants. I could change the default to: Map size = tiny -> no Iberian walls, map size = small -> Iberians get towers only, map size medium or greater -> Iberians get full walls.

    Feedback welcome...

  10. Someone was working on new water rendering code that realistically renders water depth correctly. There haven't been any recent updates though.

    That was me, Mythos. Updates aren't really needed, the code is pretty much there. There's a patch in Trac, it just need to be tested against the latest SVN, as it's quite old now... The only last thing to touch up were the waves but they're already "quite" good.

    Ah, yes, I remember.

    About water effects: is there some map using the recently added waterfalls and "lakes" (other than the test map).

    In random maps the coordinate for the hight cannot be set so I don't think they can be used easily. The waterfall in addition needs the terrain to be shaped as the fall to look well, so it's even harder to use.

    Here's a new version, changes:

    - Added a darker more fitting terrain between the light grass and the water surroundings like Wraitii suggested.

    - Added bushes to the water surroundings so players without high ground near (forests) will still have access to wood though less.

    - Added berry bushes and cypresses as start resources next to the players (not sure if I should have used grapes/apple trees/other (wood) trees instead/additionally).

    Players now all have access to wood but not equally high. It should by far be enough to reach town state. After that players with less access to wood will have more stone/metal so it will be about balanced I think.

    A bit off topic:

    - Some buildings (like e.g. civil centres) in part "fly" above the earth when placed on uneven ground. I thought/think they should have they foundation reach wide below their placement height coordinate.

    - I noticed that not all civilizations have infantry units that cost food and metal (only). I feel that should be the case (foot fir the living and metal for the arms).

    The RMS: belgian_uplands2012-9-16.zip

    ...and a screen-shot:

    post-14196-0-78343500-1347795264_thumb.j

  11. Just want to say that still not all attributes are shown - neither on the build/produce button nor in the entities tooltips:

    - Range

    - Attack rate or time

    - Number of attacks (like ships, (siege)towers, fortresses and Cevil centres)

    - Maximum garrison space (only missing for build buttons AFAIK)

    Additionally I would really like a description of what "armor" is. It's not at all clear. At least something like: "For each attack type the armor is subtracted from successful attacks but at least 1 damage is dealt ?per type?".

  12. ^ Hah that reply is just awesome.

    So from what I understand you're trying to create terrain erosion. I wonder what it would do to the buildings.

    I fear that would mainly raise the number of polygons... if at all possible. I read somewhere (http://www.golem.de/...1209-94503.html) that polygones are not needed any more, though, so it might be possible but I'm not the one to answer this question.

    And exactly what is defined as erosion? Water levels changing? Textures changing? The terrain changing as if it were a a pile of jello or a water bed?

    I should have explained a bit further x)

    E.g. that I start with a random heightmap and rescale it at the end because in the process the heightmap gets extreme flat of cause. More explained here: http://www.wildfireg...=40#entry250216

    Erosion, as I mean it here, is a change to the heightmap calculated by a function that simulates a real erosion process. The one I use here could be called "decay erosion" because it just depends on the height difference between all pairs of fields connected to each other and a portion of the difference is added to the height of the lower field and removed from the higher field - like material falling downhill. More mathematic: newHeight = oldHeight + erosionStrength * laplaceOperator(oldHeightMap, actualCoordinates)². The square in this case only means that not only appending fields in X and Y direction are compared to each field but the diagonal shifted fields are as well (German Wikipedia: http://de.wikipedia....ildverarbeitung ...can't find this in the English version). I use a map of x/y shifts to determine the fields compared to a given field: [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]. This enables me to do directed erosion, too, like sun would do (or wind when further checking if the change is down or uphill).

    But all those are to simple for lets say water gathering in streams and forming rivers. The Laplace operator is in general just div( grad( scalarField ) ) and the grad( scalarField ) gets you the direction and speed water would flow at each point of the scalar field (the height map) - generating a vector field (the water floating field). There you have to apply non-linear scaling before processing the div(). For that I wrote a javascript lib for discrete n-dimensional vector analysis inside a finite n-hypercube (with the "beginning" and "end" of each dimension wrapped together to ensure the same size of scalar and vector fields): http://www.wildfireg...=40#entry250606 . The problem is... it is MUCH to slow - I wish someone could help me with that though I fear it will always be slow with the needed self-recursive functions. So I'll implement 2D and 3D versions.

    I think in general that would be the main types of erosion to define: General decay, directed decay by the sun (so only at one side), additive/removing only directed erosion to simulate wind and the non linear streaming water erosion.

    I don't have taken into account the texture at all. That would make things more realistic by having different materials that resist more or less to different types of erosion.

    So in short: Erosion for me are changes to the heightmap and the terrain applied in a similar way like natural erosion would do.

    Of cause you could generalize "heightmap" to "surface" and "terrain" to "material" so it could be applied to entities as well.

    Those functions will be easy to use (ATM I use getBla() functions and set the heightmap to it later):

    - applyDecayErosion(strength)

    ...with strength between 0 and 1 determining how extreme each apply changes the heightmap

    - applySunErosion(strength, northVector)

    ...with north vector defining the direction the sun is coming from and it's length the average angle towards plain ground (the longer the lower over the horizon)

    - applyWindErrosion(strength, direction, type)

    ...with direction similar to the northVector (in this case where the wind is blowing towards) and type can be "additive", "subtractive" and "both"

    - applyWaterErosion(strength, nonLinearExponent)

    ...with the non linear exponent determining a scale factor strength is scaled with got by the normalized vector-fields vectors length with the exponent given by nonLinearExponent

    - rescaleHeightmap(minHeight, maxHeight)

    ...to "stretch" the heightmap after multiple erosions are applied. It's stretched in the height, ofc, not in the plain.

    An additional argument determining how often the erosion should be applied would help. Don't confuse this with strength! Strength can't be set to high values because the heightmap will wind up in self interference (with the frequency determined by the "compare field map" used) while the number of applies can be infinite (if you want to wait that long ^^) and blurs structures each time so the average size of structures will grow (and blur ofc.). To avoid the extreme blur after many erosion processes it might be a good idea to add a rescale function in X/Y direction as well.

    Additionally it might be a good idea to make erosion possible to only parts of the map...

    What I really like about it is there aren't any straight lines like in other RMS maps, and it's also asymmetrical, which I'm a big fan of.

    Me too! I like balanced as well but I hope that's not to contradicting.

    (We really need that texture blending upgrade)

    To smother blend two textures at the edges? At least I noticed that textures look quite unnatural in some cases showing the edges of the tiles.

  13. It's amazing what some people can do with "just" some lines of code :)

    I'm honored :thank_you2:

    Indeed this map contains less code then most others ^^

    Another awesome map dude. Just love the landscape. Plus its not too hard on my computer :)

    Thx, I'll do my best!

    Nice job. The only thing that remains is that to make it playable. :thumbsup:

    Yes, and there are still some unresolved problems... (see below)

    it's a good start, but maybe lakes should be always deeper at the center

    That would need non-linear scaling or it will become a water map ^^

    I'm working on general functions to deal with such things.

    May I know why it's so important for you? :slow:

    Could use a lower amount of rock actors and a transition terrain between the lake surroundings and the grass. Could use different grass patches.

    Also: the forest are really not fairly placed.

    Rocks/gold: I haven't play-tested yet. I will see to that.

    Transition terrain: Yep, it's quite a rough change. Easy to do.

    Different grass patches: There are two "grass types": low (a bit lighter) and high (a bit darker). Both contain at least 4 types of terrain. That seams enough to me. If you mean patches of other type on the same height: Not ATM. I try to keep things simple until the general functions are tested well.

    Not fair: Yes, that's a problem that may be not so easy to resolve. However, the map description warns you. This aproach is more to look natural then to be balanced. But I like balanced maps and I'm thinking about how to fix that but not at highest priority right now.

    We need that water depth code soon. ;)

    Could someone please tell me what's so darn important about water depth? :1eye:

    Or do you mean the general change of heightmap and SEA_LEVEL in rmgen??? :scratch_one-s_head:

    Well...

    Here's a new version with the players placed valid. That in no way means something like "balanced". Indeed there are many problems left:

    (1) Very unequal derivation of resources across the map.

    Possible solutions: Adding a tilting function may change the hight derivation to be more equal across the map. In this map it would be the wood to be balanced.

    (2) Player start positions are not always close to wood.

    Possible solution would be to add a check if wood is inside a current distance of each start position. The amount, however, could still differ much.

    A simpler method would just be to add some "civilizes" wood with the starting entities (like some cypresses).

    Another solution would be to add more wood to the lakes surroundings. That leads to the next problem...

    (3) Stone and metal entities are bigger than a tile. If wood and stone is put in the same "random terrain" the wood might wind up unreachable inside the stone/metal entity.

    Possible solution: Don't place different resource types in the same random terrain... but that is a bad restriction IMO.

    (4) To ensure valid player starting positions much space is left on the map.

    Guess I have to do some finer decoration at the end.

    Here's the map: belgian_uplands2012-9-12.zip

    And a screen shot of a more balanced seed (9) of a medium map with 4 players:

    post-14196-0-69699700-1347483783_thumb.j

    Keep burning! :wheelchair:

    • Like 1
  14. This map is based on the simplest way to do erosion. It is more experimental but I thought it might be worth an announcement. The random map script itself is not playable, yet, but some seeds might be (e.g. 2110).

    EDIT: Short description of the heightmap generation: Set each tile to a random height -> apply decay erosion several times (about 50 + mapSize / 4) -> rescale the heightmaps height because the erosion process flattens it.

    Further explanations:

    http://www.wildfireg...=40#entry250216

    http://www.wildfireg...35

    Random map: belgian_uplands2012-9-10.zip

    Map of the "playable" seed 2110: belgian_uplands_seed2110.zip

    A sceenshot of seed 2110:

    post-14196-0-78457800-1347313713_thumb.j

    EDIT: A new more playable version can be found later in this post (I might sometimes be to lazy to link to the newest version :whistling:):

    Ticket with the newest files attached: http://trac.wildfiregames.com/ticket/1688

    • Like 1
  15. I wrote a rmgen lib to support n-dimensional discrete vector analysis e.g. for simulating floating water erosion.

    I'm not quite sure that's the best way to do it and I am sure it's not the fastest/best readable code.

    I hope for someone more into programming/javascript to give me tips how to do better (but please without removing the generalized approach).

    Indeed it might be possible to do all this with vector algebra as well and for that fully documented javascript libs might be out there so if anyone has information about that, plz let me know.

    Here's the code (indentation missing due to erased tabs):


    //////////
    // Discrete vector analysis functionality
    //////////

    /*
    getScalarField
    Generate an n-dimensional discrete hypercubic scalar field of the given size.
    Arguments:
    dimension: The dimension of the field
    size: The "width" of the hypercube containing the field
    defaultValue: The value all scalars in the field (so it's always flat and don't contain undefined values)
    */
    function getScalarField(dimension, size, defaultValue)
    {
    dimension = (dimension || 2);
    size = (size || mapSize + 1); // Default for heightmaps
    defaultValue = (defaultValue || 0);
    var scalarField = defaultValue;
    for (var d = 0; d < dimension; d++)
    {
    var newScalarField = [];
    for (var s = 0; s < size; s++)
    newScalarField.push(scalarField)
    scalarField = deepcopy(newScalarField);
    }
    return scalarField;
    }

    /*
    getVectorField
    Generate an n-dimensional discrete hypercubic vetor field of the given size.
    Arguments:
    dimension: int, The dimension of the field
    size: int, The "width" of the hypercube containing the field (So float coordinates are not supported!)
    defaultValue: float, The value all vectors components in the field (So div and curl of this vector field is always 0 and vectors are colinear to (1, 1, 1, ...) or the 0-vector)
    */
    function getVectorField(dimension, size, defaultValue)
    {
    dimension = (dimension || 2);
    size = (size || mapSize + 1); // Default for heightmaps
    defaultValue = (defaultValue || 0);
    var vector = [];
    for (var d = 0; d < dimension; d++)
    vector.push(defaultValue);
    var vectorField = vector;
    for (var d = 0; d < dimension; d++)
    {
    var newVectorField = [];
    for (var s = 0; s < size; s++)
    newVectorField.push(vectorField)
    vectorField = deepcopy(newVectorField);
    }
    return vectorField;
    }

    /*
    getDimensionOfField
    Takes an discrete hypercubic scalar or vector field and returns it's dimension.
    */
    function getDimensionOfField(field)
    {
    var nextDepthObject = deepcopy(field);
    var size = field.length;
    var dimension = 0;
    while (typeof(nextDepthObject) == "object")
    {
    if (nextDepthObject.length == size)
    {
    dimension++;
    nextDepthObject = nextDepthObject[0];
    }
    else
    break;
    }
    return dimension;
    }

    function getAllCoordinatesInHypercube(dimension, size)
    {
    var coordinates = [];
    for (var i = 0; i < Math.pow(size, dimension); i++)
    {
    var vector = [];
    var sum = 0
    for (var d = 0; d < dimension; d++)
    {
    vector.push(((i - sum) % (Math.pow(size, d + 1))) / Math.pow(size, d));
    sum += vector[d]*Math.pow(size, d);
    }
    coordinates.push(vector);
    }
    return coordinates;
    }

    function getVectorLength(vector)
    {
    var squareSum = 0;
    for (var d = 0; d < vector.length; d++)
    squareSum += Math.pow(vector[d], 2);
    return Math.pow(squareSum, 1/2);
    }

    function getFieldValueByCoordinate(field, vector)
    {
    var dimension = vector.length;
    var size = field.length;
    var value = deepcopy(field);
    for (var d = 0; d < dimension; d++)
    {
    value = value[vector[d]];
    }
    return value;
    }

    function setFieldValueByCoordinate(field, vector, value)
    {
    var coordinate = vector.shift();
    if (vector.length == 0)
    field[coordinate] = value;
    else
    setFieldValueByCoordinate(field[coordinate], vector, value);
    }

    function getNormalizedField(field, scaleToLength, isVectorField)
    {
    scaleToLength = (scaleToLength || 1);
    var dimension = getDimensionOfField(field);
    var size = field.length;
    var coordinates = getAllCoordinatesInHypercube(dimension, size);
    isVectorField = (isVectorField || typeof(getFieldValueByCoordinate(field, coordinates[0])) == "object");
    var maxLength = 0;
    for (var i = 0; i < coordinates.length; i++)
    {
    if (isVectorField)
    var length = getVectorLength(getFieldValueByCoordinate(field, coordinates[i]));
    else
    var length = abs(getFieldValueByCoordinate(field, coordinates[i]));
    if (length > maxLength)
    maxLength = length;
    }
    var newField = deepcopy(field);
    for (var i = 0; i < coordinates.length; i++)
    {
    if (isVectorField)
    {
    var newValue = [];
    for (var d = 0; d < dimension; d++)
    newValue.push(getFieldValueByCoordinate(field, coordinates[i])[d] / maxLength * scaleToLength);
    }
    else
    var newValue = getFieldValueByCoordinate(field, coordinates[i]) / maxLength * scaleToLength;
    setFieldValueByCoordinate(newField, coordinates[i], newValue);
    }
    return newField
    }

    /*
    getGrad
    Returns the gradient of a given discrete hypercuibic scalar field, a discrete hypercubic vector field (gradient field). Dimension might depend on method: scalar fields width or the same - 1.
    Problems:
    The calculated vectorfield would be of size sizeOfScalarField - 1. To avoid this the left is wrapped to the right and the bottom to the top.
    Using 2 appending fields results in a shift of shiftVector = 1/2*(1, 1, 1, ... , 1), abs(shiftVector) = 1/2*sqareroot(dimension) between the given scalar and the resulting vector field.
    Using the 2 fiels appending the given tile avoids the shift but results in 2 areas independent of each other shifted towards each other by 1. I don't know if that is bad.
    It might be a good idea to include the diagonal appending tiles for calculation to couple those two independent areas...
    */
    function getGrad(scalarField, dimension, size)
    {
    dimension = (dimension || getDimensionOfField(scalarField));
    size = (size || scalarField.length);
    var vectorField = getVectorField(dimension, size);
    var coordinates = getAllCoordinatesInHypercube(dimension, size);
    for (var i = 0; i < coordinates.length; i++)
    {
    var vector = [];
    for (var d = 0; d < dimension; d++)
    {
    var addCoordinate = deepcopy(coordinates[i]);
    addCoordinate[d] = (addCoordinate[d] + 1) % size;
    var subCoordinate = deepcopy(coordinates[i]);
    subCoordinate[d] = (subCoordinate[d] - 1 + size) % size;
    vector.push(getFieldValueByCoordinate(scalarField, addCoordinate) - getFieldValueByCoordinate(scalarField, subCoordinate));
    }
    setFieldValueByCoordinate(vectorField, coordinates[i], vector);
    }
    return vectorField;
    }

    // Same problems like in getGrad so all dimensions wrapped and the actual coordinates value ignored
    function getDiv(vectorField, dimension, size)
    {
    dimension = (dimension || getDimensionOfField(vectorField));
    size = (size || vectorField.length);
    var scalarField = getVectorField(dimension, size);
    var coordinates = getAllCoordinatesInHypercube(dimension, size);
    for (var i = 0; i < coordinates.length; i++)
    {
    var value = 0;
    for (var d = 0; d < dimension; d++)
    {
    var addCoordinate = deepcopy(coordinates[i]);
    addCoordinate[d] = (addCoordinate[d] - 1 + size) % size;
    value += getFieldValueByCoordinate(vectorField, addCoordinate)[d];
    var subCoordinate = deepcopy(coordinates[i]);
    subCoordinate[d] = (subCoordinate[d] + 1) % size;
    value -= getFieldValueByCoordinate(vectorField, subCoordinate)[d];
    }
    setFieldValueByCoordinate(scalarField, coordinates[i], value);
    }
    return scalarField;
    }

    ...and the ziped rmgen lib: discreteVectorAnalysis2012-9-10.zip

    And some test code:


    //////////
    // Test discrete vector analysis functionality
    //////////
    var testScalarField = getScalarField(2, 5); // Get an "empty" scalar field (all values = 0)
    var testCoordinates = getAllCoordinatesInHypercube(2, 5); // Get all valid (integer) coordinates of the area the field is defined in
    for (var i = 0; i < testCoordinates.length; i++)
    setFieldValueByCoordinate(testScalarField, testCoordinates[i], randInt(-9, 9)); // Ranomize the scalar fields values
    var gradField = getGrad(testScalarField); // Get the gradient field (a vector field) determining the slope in each coordinated direction (or the direction water would flow)
    var divGradField = getDiv(gradField); // Get the divergence of the gradient field (Would be something like how much water will leave this coordinate more then gathered from other coordinates)
    var normalizedTestScalarField = getNormalizedField(testScalarField); // Normalized version, needed for non-linear effects e.g. roughtly considering friction
    var normalizedGradField = getNormalizedField(gradField); // Normalized version, needed for non-linear effects e.g. roughtly considering friction
    var normalizedDivGradField = getNormalizedField(divGradField); // Normalized version, needed for non-linear effects e.g. roughtly considering friction
    log("uneval(testScalarField) = " + uneval(testScalarField));
    log("uneval(normalizedTestScalarField) = " + uneval(normalizedTestScalarField));
    log("uneval(gradField) = " + uneval(gradField));
    log("uneval(normalizedGradField) = " + uneval(normalizedGradField));
    log("uneval(divGradField) = " + uneval(divGradField));
    log("uneval(normalizedDivGradField) = " + uneval(normalizedDivGradField));

    EDIT:

    One problem is that defining divergence and gradient would shift the field by 1/2 of the maximum cell diameter of the grid and reduce the size of the hypercube the field is defined in by 1. The size reduction can be avoided by "wrapping" the cube's side in each dimension e.g. wrapping the left to the right. The shift comes from taking the difference of the cell itself to an appending field in each dimensions direction. So the "point" where the calculation "takes place" is between the cells. The shift can be avoided by ignoring the field the operation is applied to and use the previous and next field instead. That however leads to two decoupled grids like black and white fields on a chess board. Using such a decoupled approach for erosion leads to two smooth fields stacked in each other and together are extremely rough (so nothing is gained). The decoupling could be avoided by also taking into account the diagonal differences (like the last example here: http://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_in_Image_Processing )

  16. Now that I got my 3D support back today I had to try something

    Here's the result of a first approach to generate a more realistic/random looking reliefmap/heightmap/terrain shape. It's only generated by a total scratchy random heightmap with a (very simple) erosion function flattening it several times (and sanely rescaling it at the end). The type of erosion is more like cracked rocky earth after an earthquake is decaying from sun erosion and a bit of random wind/quakes that make the material fall down. So it looks more like sandy ground without much wind and without water that gathers in streams. I'm going to add other erosion types later. In addition, to make cliffs possible, I think about filling in some geological activity like plates shifting or lava bubbles hovering ground. But here's what this very early state with only a few lines of code throw out:

    post-14196-0-36483300-1346973519_thumb.j

    ...and the random map: fexor_hightmap.zip

    Of cause it is very hard to predict how such random terrains look like and it will take some effort to make it well playable but I think that will be possible.

    EDIT:

    More interesting structures can be got with directed erosion (similar to wind would do):

    post-14196-0-45554300-1347020781_thumb.j

    The screenshot shows the map generated by fexor_hightmap2012-9-7.zip with seed 5201.

    EDIT:

    An additional screenshot of a relief map generated with only subtracting directed erosion with terrain painted by height.:

    post-14196-0-54858800-1347277981_thumb.j

    ... the scale does not fit the unit/building sizes, yet.

    EDIT:

    A simple "playable" map done with erosion can be found here: http://www.wildfiregames.com/forum/index.php?showtopic=16535

  17. Ok, so now we know it's definitely a driver issue. Also, the "draw_vbo" function call means this is VBO-related as I suspected.

    You might want to try testing the configuration that works for you with "novbo = true", just to see what happens.

    With preferglsl and novbo = true I still got the same 3 "minor" issues:

    - Distant ground textures look strange,

    - Sometimes black polygones on the ground.

    - Sometimes building parts are seen-through.

    And try this on Windows with a different driver when you get the chance, just to make sure this is indeed the driver's fault.

    I'm pretty sure it will work all right with the official drivers. Will let you know...

    Not much else we can do right now, I'm afraid. I'll check the memory alignment in the renderers over the weekend and push any changes to git, as that could help a bit (doubt it).

    Thanks for your patience, FeXoR.

    You'r welcome, Thanks for yours.

  18. Oh sorry, you need to type "r" to run it.

    I do:

    Change local.cfg to:


    gentangents = true
    preferglsl = true
    # novbo = true
    # silhouettes = true
    # smoothlos = false

    - Bash console: Go to [sVN-Path]/binaries/system

    - Bash console: gdb --args ./pyrogenesis -editor

    - gdb console: r -> Atlas opens

    - Generate NEW RMS Test -> Atlas gets stuck but stays open grayed off (not reacting)

    - Take a sceen shot:

    post-14196-0-38246800-1345045318_thumb.p

    - gdb console: bt -> got some output

    - gdb console: q -> Askes to kill Atlas

    - I agree -> Atlas closes, back to bash console.

    - Copy output:

    fexor@gosarus:~/dat/projekte/0ad-linux/binaries/system$ gdb --args ./pyrogenesis -editor

    GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2) 7.4-2012.04

    Copyright © 2012 Free Software Foundation, Inc.

    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

    This is free software: you are free to change and redistribute it.

    There is NO WARRANTY, to the extent permitted by law. Type "show copying"

    and "show warranty" for details.

    This GDB was configured as "i686-linux-gnu".

    For bug reporting instructions, please see:

    <http://bugs.launchpad.net/gdb-linaro/>...

    Reading symbols from /media/dat/projekte/0ad-linux/binaries/system/pyrogenesis...done.

    (gdb) r

    Starting program: /media/dat/projekte/0ad-linux/binaries/system/pyrogenesis -editor

    [Thread debugging using libthread_db enabled]

    Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".

    TIMER| LoadDLL: 1.37349 s

    [New Thread 0xb4fe7b40 (LWP 8493)]

    [New Thread 0xb44feb40 (LWP 8494)]

    [New Thread 0xb3affb40 (LWP 8495)]

    Cache: 200 (total: 2770) MiB

    [New Thread 0xa61dfb40 (LWP 8496)]

    TIMER| InitVfs: 10.207 ms

    [New Thread 0xa59b5b40 (LWP 8497)]

    [Thread 0xa59b5b40 (LWP 8497) exited]

    [New Thread 0xa59b5b40 (LWP 8498)]

    [New Thread 0xa11a3b40 (LWP 8499)]

    TIMER| InitScripting: 4.89476 ms

    TIMER| CONFIG_Init: 13.5491 ms

    [New Thread 0xa03ffb40 (LWP 8500)]

    [New Thread 0x9dd97b40 (LWP 8501)]

    TIMER| RunHardwareDetection: 24.6825 ms

    [New Thread 0x9d1ffb40 (LWP 8504)]

    TIMER| InitRenderer: 12.7747 ms

    TIMER| ps_console: 23.9604 ms

    TIMER| ps_lang_hotkeys: 1.77956 ms

    TIMER| common/emptyinit.xml: 11.1252 ms

    GAME STARTED, ALL INIT COMPLETE

    [New Thread 0x97affb40 (LWP 8505)]

    [Thread 0x97affb40 (LWP 8505) exited]

    TIMER| ParseTerrain: 5.53813 ms

    TIMER| LoadDLL: 199.129 ms

    TIMER| ParseEntities: 3.68389 s

    GAME STARTED, ALL INIT COMPLETE

    Program received signal SIGSEGV, Segmentation fault.

    [switching to Thread 0xb4fe7b40 (LWP 8493)]

    0x9f8bb47a in ?? () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    (gdb) bt

    #0 0x9f8bb47a in ?? () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    #1 0x9f8b85c4 in ?? () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    #2 0x9f8ba36d in draw_pipeline_run () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    #3 0x9f944897 in ?? () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    #4 0x9f944930 in ?? () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    #5 0x9f8c5b64 in ?? () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    #6 0x9f8bf3fb in ?? () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    #7 0x9f8bf72d in draw_vbo () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    #8 0x9f8892d0 in ?? () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    #9 0x9f88b3fd in ?? () from /usr/lib/i386-linux-gnu/dri/r300_dri.so

    #10 0x9f2181da in st_draw_vbo () from /usr/lib/i386-linux-gnu/dri/libgallium.so

    #11 0x9f6dcf5d in ?? () from /usr/lib/i386-linux-gnu/dri/libdricore.so

    #12 0x9f6dd098 in ?? () from /usr/lib/i386-linux-gnu/dri/libdricore.so

    #13 0x9f6dd1cf in ?? () from /usr/lib/i386-linux-gnu/dri/libdricore.so

    #14 0x082fd0c1 in InstancingModelRenderer::RenderModel (this=0x99f497b8, shader=..., model=0x94773848)

    at ../../../source/renderer/InstancingModelRenderer.cpp:357

    #15 0x082add1f in ShaderModelRenderer::Render (this=0x9af348b8, modifier=..., context=..., flags=8) at ../../../source/renderer/ModelRenderer.cpp:715

    #16 0x082b869e in CallModelRenderers (flags=8, context=..., this=0xb46c8e50) at ../../../source/renderer/Renderer.cpp:360

    #17 CRenderer::RenderSilhouettes (this=0xb4659e08, context=...) at ../../../source/renderer/Renderer.cpp:1265

    #18 0x082b99a5 in CRenderer::RenderSubmissions (this=0xb4659e08) at ../../../source/renderer/Renderer.cpp:1483

    #19 0x082ba0c6 in CRenderer::RenderScene (this=0xb4659e08, scene=...) at ../../../source/renderer/Renderer.cpp:1675

    #20 0x0823768a in CGameView::Render (this=0x9c3ae780) at ../../../source/graphics/GameView.cpp:494

    #21 0x081cd40b in Render () at ../../../source/ps/GameSetup/GameSetup.cpp:217

    #22 0x08330f45 in AtlasViewGame::Render (this=0x99ba3128) at ../../../source/tools/atlas/GameInterface/View.cpp:262

    #23 0x08326bd9 in RunEngine (data=0xbffff0c8) at ../../../source/tools/atlas/GameInterface/GameLoop.cpp:227

    #24 0xb7652d4c in start_thread () from /lib/i386-linux-gnu/libpthread.so.0

    #25 0xb7590ace in clone () from /lib/i386-linux-gnu/libc.so.6

    (gdb) q

    A debugging session is active.

    Inferior 1 [process 8490] will be killed.

    Quit anyway? (y or n) y

    fexor@gosarus:~/dat/projekte/0ad-linux/binaries/system$

  19. As long as materialmgr.quality is zero, GLSL shouldn't need tangents, but won't try to do anything fancy (I should have asked you to try that earlier). It's really strange that the supposedly "stable" ARB mode doesn't work for you, yet GLSL mode does.

    For a stacktrace, pick the options that make the game crash and then run the game with gdb


    gdb --args ./pyrogenesis -editor

    Once it crashes, type in "bt" and copy the result.

    Not sure if that worked. Atlas didn't open. Here's the console output:


    fexor@gosarus:~/dat/projekte/0ad-linux/binaries/system$ gdb --args ./pyrogenesis -editor
    GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2) 7.4-2012.04
    Copyright (C) 2012 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law. Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "i686-linux-gnu".
    For bug reporting instructions, please see:
    <http://bugs.launchpad.net/gdb-linaro/>...
    Reading symbols from /media/dat/projekte/0ad-linux/binaries/system/pyrogenesis...done.
    (gdb) bt
    No stack.
    (gdb) q
    fexor@gosarus:~/dat/projekte/0ad-linux/binaries/system$

×
×
  • Create New...