Scene .SCO Toolset - heightmap converters, object placers, and texture importers! Oh my!

Users who are viewing this thread

Disgrntld said:
Looks really good, Swyter!

One small issue, though. From my understanding, the terrain code defines a procedurally-generated base terrain, call it A. The SCO file contains the modification terrain, B, that when added to A produces the final terrain, C. So, C = A + B.

With scoWriter, we can modify B. However, we want our heightmap to define C. Well that sounds simple enough to fix, we think. We'll just subtract A from the heightmap before we dump it in (B = heightmap - A && C = A + B => C = heightmap). Alas, that's the rub. We don't have A. It's generated by code we're not privy to. This mean that there will be small undulations in C.

I did think of a way around that, though. We use the Mount&Blade editor to flatten our terrain. These terrain modifications are stored in B, and the end result is B = -A. Then, instead of overwriting B with our heightmap, we _add_ our heightmap to the existing B (B = -A + heightmap && C = A + B => C = heightmap).

Basically, I think you should add the heightmap to existing B so people can feed in pre-flattened SCOs.

Thanks mate. Yours is the inspiration and a good part of the implementation.

I think that the terrain generator just uses some kind of perlin noise with the seeds provided, surely cmpxchg8b can help us with that one.

But what you're saying can be already done using the image editor itself. Photoshop and Gimp have additive and substantive layer modes, that you can use for that. Not only for giving your cousin's photo album a bloom effect. :smile:

______
Anyways, altering the terrain key for getting out the hills is trivial. Even more with the online, client-side tool I'm finishing right now:
Code:
http://mbcommands.ollclan.eu/terrain/terrainkey_cleanup.html

Just ensure you're using a HTML5 compatible browser. Firefox still doesn't supports sliders. It's read only at the moment.
If you know how to open the console (F12 + Esc in Chrome) it will show you a complete log of the decrypted key.
 
Ah, but the issue is that we don't have the data to subtract in the image editor. It's A, which Mount&Blade generates internally from the terrain code. The only way I know how to get it is by letting Mount&Blade generate the negative for us when we flatten a map in the editor (so it'll be stored in B, i.e. B = -A). This is unless cmpxchg8b or someone knows how we could generate our own A.

I suppose I'll admit how I stumbled across this now. I might have been generating Titty Mountain from a heightmap and gotten wrinkly boobs from the base terrain. :lol:

7qgok.jpg
EDIT: Whoops, didn't see the bottom of your post about your terrain code tool. First off, bad ass, should be mighty useful! However, I dunno if it'll solve the problem because I couldn't seem to create a code that generated a completely flat terrain. Maybe it was just me, though.
 
Disgrntld said:
Ah, but the issue is that we don't have the data to subtract in the image editor. It's A, which Mount&Blade generates internally from the terrain code. The only way I know how to get it is by letting Mount&Blade generate the negative for us when we flatten a map in the editor (so it'll be stored in B, i.e. B = -A). This is unless cmpxchg8b or someone knows how we could generate our own A.

I suppose I'll admit how I stumbled across this now. I might have been generating Titty Mountain from a heightmap and gotten wrinkly boobs from the base terrain. :lol:

7qgok.jpg

:shock: :shock: :shock:

That's some intensive map editing going right there. :smile:
It's multiplayer?

Ohhh. About getting the "negative", you meant the generator, I was talking about flattening it manually using the leveling tool, export it to png, and then add it to your heightmap using any image editing software. That may work, and it's very user friendly.
 
:grin:

That was before I got the scale sorted out, so it was scrapped. However, here's the training map I'm working on for the Reddit Brigade. I might include Titty Mountain off at the back. We'll see how the brigade reacts.

And yea, exporting flattened to PNG would totally work, fair enough!
 
Okay, all set!.

Articles written, documentation enhanced, mirror done and tool page created.
Take a look here and feel free to make all the additions you want:

<
Code:
http://mbmodwiki.ollclan.eu/SceneObj
>

...and here...

<
Code:
http://mbmodwiki.ollclan.eu/Scene_Heightmap_Imp/export_Tools
>


Also, can you change the first post's title to reflect all the stuff going on here? :smile:
It will help people to find this earlier and... probably generates a bit more of buzz over the mapper's guild.
 
Totally awesome :smile:  Will spend time with it Sunday evening, when I'm finally free again- this is really going to be helpful for a lot of things I've been wanting to try out :smile:
 
Done, Swyter!

Also, I dunno if you're interested in adding texture importing too, but here's what I used:
Code:
void set_layer(ground_paint_t *ground_paint, int layer, tga_data_t *map)
{
	int max = ground_paint->size_x * ground_paint->size_y;

	if(ground_paint->layers[layer].cells == NULL) {
		ground_paint->layers[layer].continuity_count = malloc((max + 1) * sizeof(int));
		ground_paint->layers[layer].cells = malloc(max * sizeof(float));
	}

	ground_paint->layers[layer].continuity_count[0] = max;
	ground_paint->layers[layer].continuity_count[max] = 0;

	int x, y;
	for(y = 0; y < ground_paint->size_y; ++y)
	{
		for(x = 0; x < ground_paint->size_x; ++x)
		{
			int offset = (y * map->w + x) * map->depth / 8;
			short int r = map->data[offset];
			short int g = map->data[offset + 1];
			short int b = map->data[offset + 2];
			if(r != g || g != b) {
				printf("ERROR: map was not grayscale\n");
				return;
			}
			ground_paint->layers[layer].cells[x * ground_paint->size_y + y] = r / 255.0f;
		}
	}
}
It doesn't make use of the autofill functionality yet, but it doesn't seem like that would affect performance that much, just file size. Also, it shows how to use the convention of adding the autofill number to the extra space I left at the end of continuity_count (which was why I modified scoReader, to be able to remember whether the read texture values were autofilled or not).
 
Disgrntld said:
Done, Swyter!

Also, I dunno if you're interested in adding texture importing too, but here's what I used:
Code:
void set_layer(ground_paint_t *ground_paint, int layer, tga_data_t *map)
{
	int max = ground_paint->size_x * ground_paint->size_y;

	if(ground_paint->layers[layer].cells == NULL) {
		ground_paint->layers[layer].continuity_count = malloc((max + 1) * sizeof(int));
		ground_paint->layers[layer].cells = malloc(max * sizeof(float));
	}

	ground_paint->layers[layer].continuity_count[0] = max;
	ground_paint->layers[layer].continuity_count[max] = 0;

	int x, y;
	for(y = 0; y < ground_paint->size_y; ++y)
	{
		for(x = 0; x < ground_paint->size_x; ++x)
		{
			int offset = (y * map->w + x) * map->depth / 8;
			short int r = map->data[offset];
			short int g = map->data[offset + 1];
			short int b = map->data[offset + 2];
			if(r != g || g != b) {
				printf("ERROR: map was not grayscale\n");
				return;
			}
			ground_paint->layers[layer].cells[x * ground_paint->size_y + y] = r / 255.0f;
		}
	}
}
It doesn't make use of the autofill functionality yet, but it doesn't seem like that would affect performance that much, just file size. Also, it shows how to use the convention of adding the autofill number to the extra space I left at the end of continuity_count (which was why I modified scoReader, to be able to remember whether the read texture values were autofilled or not).

Cool stuff, mate. I see that you use your own tga reader (it's an easy format to parse I've heard of). I stuck with
Code:
stb_image
for completeness, the good thing is that it tells you the number of channels and so. The truth is that I didn't paid much attention to the continuity count, that's an huge mistake, I know.

Now I see that it's a sort of cheap run-length encoding, much like the TGA compression itself. :smile:

So, thankies.

I didn't needed the texture painting for the proof of concept, but getting it working with my implementation is as easy as change the layer loop for the right magic (
Code:
ground_spec_no==GROUND_PAINT_MAGIC
) and just append the
Code:
ground_spec_id
s to the filename. And some other little tweaks.

I'll do a revision later implementing the RLE, fixing the horizontally reversed output of the exporter and optionally exporting the ground specs, or... do it yourself, as you want!

@xenoargh: Tell us what you think! This time you are the beta tester. :razz:

EDIT: And, seriously what
Code:
leveling_magic
is supposed to do? The output doesn't makes much sense to me...
Code:
#define GROUND_PAINT_LEVELING_MAGIC -12565
 
No idea why the engine calls it leveling, possibly remains of something older. It's actually the color layer, and you have to parse cells as unsigned ints (AARRGGBB) instead of floats.
 
cmpxchg8b said:
No idea why the engine calls it leveling, possibly remains of something older. It's actually the color layer, and you have to parse cells as unsigned ints (AARRGGBB) instead of floats.
Oh, it's the vertex coloring? I completely forgot that.

Actually the first time I got exporting working I thought that the SCO was broken, as it outputted random zones in 0/1 fashion.
Misleading names. Thanks for the heads-up.
 
That looks very amazing guys!

Love it, could turn out very usefull for some maps.
 
This is really awesome. It really allows you to come up with some interesting Battlefields. Great work!
 
The main reason I wanted it, Comrade Temuzu, was to utilize terrain generation programs like World Machine.

EDIT #1: For example, everything in this was made from this and the object placer example.

EDIT #2: cmpxchg8b and Swyter, I applied for this to be moved to the Unofficial Editing Tools sub-forum. We're going to be famous! ;P
 
Definitely looking forwards to breaking testing this out on Sunday night; great stuff thus far.  Like I said, there are a lot of things I've left off my plate because of the lack of a way to do this quickly and easily.

One question, though:  on the scale from 0-255, where is the water level, if using the default water level of -0.5 meters?
 
xenoargh said:
One question, though:  on the scale from 0-255, where is the water level, if using the default water level of -0.5 meters?

Take a look:
Code:
foo[count]=(float)src->ground_paint->layers[gol].cells[gox * y + goy] + 16.0f; //! I think that leaving that margin for negative terrain is enough, there's going to be a precission lost anyway.

You can tune it accordingly, tho.
Don't forget to do the same with the re-importer!

Disgrntld said:
EDIT #2: cmpxchg8b and Swyter, I applied for this to be moved to the Unofficial Editing Tools sub-forum. We're going to be famous! ;P
Where it belongs... :smile:
 
I've tried it out yesterday, works pretty great. Good work guys!

Though, it is quite hard to get the height of the terrain right. Somehow my hills always were much higher than I wanted them to be.
I tried turning the brightness down, but it didnt work to well...
 
It probably needs a scalar value and a top / bottom range value, scaling the rest of it within the high and low if defined.  With 256 values, it'd probably be best to have the default be about 0.25 or even 0.125 meters; that's still 32 meters of total height, which is quite a bit, while allowing for gentle ranges in height where it would be appropriate. 

The basic problem here very straightforward, though; it's not possible to do certain things without using 16-bit heightmaps for a lot more precision.  It'd be really interesting to output 16-bit heightmaps from World Builder or other tools for doing things like erosion simulation, if it could be coupled with some controls over what texture is presented and at what strength.  With a bit of tweaking, fairly realistic results could probably be obtained.

There are some other considerations there, though, due to the funky way that works and the fact that maps have the primary requirement of being good places to play on :smile:
 
This is kind of World Machine specific, but try the following:
Code:
// 100 is the max height in-game, 886 is the max height used in your terrain software, 2625 is the max height available in your terrain software, and 1 is the water depth
sco_file.ground_paint->layers[lcv].cells[x * sco_file.ground_paint->size_y + y] += 100.0f * 886.0f / 2625.0f * r / 255.0f - 1.0f;
The idea is to convert discrete terrain generation values into the desired, continuous range in-game. Basically, after you've finished with your terrain in World Machine, add a Clamp device and click Find Extents to determine the max height used (886 in the example). Next, click the World Extents and Resolution button and the max height available will be under the General Setup tab. Then, right before your Height Output device, add an Equalizer device. This will allow you to use all the precision available.

The ratio, 886/2625, will rescale the discrete, equalized values into the appropriate, continuous range from 0-1. Multiply by the range of height you want in-game (100 in this case, the units seem on par with meters), and subtract it to the water depth you want (I think below 2 is deep enough to fully submerge players).
 
Tested :smile:

Procedure:  copied a SCO from mod SceneObj file to location of Scopng.  Dragged SCO onto Scopng. 

Result:  a brief trip to the Console; no other output.  Are the directories non-relative, or did it crash during PNG creation?
 
Back
Top Bottom