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

Users who are viewing this thread

Swyter said:
I don't know why I expected something less arcane,... and full of hacks.
In my experience the majority of hacks are a result of the code being modified over time; however, even a small change to the generation algorithms can result in a completely different terrain, so I assume that code has remained largely unchanged since the early days of Mount&Blade...
 
cmpxchg8b said:
Swyter said:
I don't know why I expected something less arcane,... and full of hacks.
In my experience the majority of hacks are a result of the code being modified over time; however, even a small change to the generation algorithms can result in a completely different terrain, so I assume that code has remained largely unchanged since the early days of Mount&Blade...

That surely means that "Mount&Blade 2: Revamped: Look my Graphics" isn't going to be compatible at all.
And, it's me or the code base started from a DirectX 9 SDK tech example? I mean, look at the menus :smile:
 
In my experience the majority of hacks are a result of the code being modified over time; however, even a small change to the generation algorithms can result in a completely different terrain, so I assume that code has remained largely unchanged since the early days of Mount&Blade...
Yeah, it works (on most hardware) and it's straightforward (if a bit inefficient here and there) so why bother writing a new one from scratch?  Totally understandable.  It's not how I would have designed it, personally, but then again, I wouldn't have kept Warband tied to the outdated Pixel Shader 2.0 specification, either.  That's always a tough call for game developers, though; go too far ahead of players' hardware and you can get badly burned.

That surely means that "Mount&Blade 2: Revamped: Look my Graphics" isn't going to be compatible at all.
They've already said as much; no more Module System (which I for one think is a really good thing) and presumably a lot of the guts are going to get reworked.  I suspect it will be pretty much a new engine in a lot of ways.  The success of Warband has hopefully given them plenty of funding to spend their time reworking the critical areas :smile:

Even more OT:  I am a little worried about what their new body system's going to mean for people wanting to develop content for it, but that's a bridge that will have to get crossed when / if they start discussing how it works and how modders can build content to work with it.
 
Swyter said:
And, it's me or the code base started from a DirectX 9 SDK tech example? I mean, look at the menus :smile:
Yes, even Armagan said that in a post.
I'm not sure what version of DirectX, though... like, why is FFP mode called DirectX 7 if there isn't a single line of DirectX 7 code? Maybe they used DirectX 7 before updating the graphics engine, but I haven't really checked.
 
It was kind of a pain to fill out the mission_object_t structs so I added a matrix transformation API similar to OpenGL. However, I believe it's limited to affine transformations as we don't transform the vertices ourselves but rather define a frame for the Mount&Blade engine to transform them later. Since this frame is non-homogeneous, I think all projective transformations are lost in place_object. If someone who can math better than me would clear that up though, I'd really appreciate it.

Anyway, here's the link and some examples:

Colosseum -
F7F4DF7B86CB6172C9D7ACFFE45A2288335788E8
A9E0272C598240434581DE108E10650CCCD1CD5A
D6A523F741E6E418D29E15C2159BD5B68B76FF35
Code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "scoReader.h"
#include "scoWriter.h"
#include "affine.h"

int main(int argc, char **argv)
{
	if(argc < 3)
	{
		printf("Usage: %s input heightmap output\n", argv[0]);
		return EXIT_FAILURE;
	}

	FILE *in = fopen(argv[1], "rb");
	FILE *out = fopen(argv[2], "wb");

	if(!in || !out)
	{
		printf("ERROR: file(s) not found\n");
		return EXIT_FAILURE;
	}

	printf("Reading %s\n", argv[1]);
	sco_file_t sco_file;
	read_sco_file(in, &sco_file);

	stack_t *stack = affine_init();

	translate(stack, 310, 277, 33.23);
	rotate(stack, -11 * M_PI / 16, 0, 0, 1);
	int lcv1, lcv2;
	int n;
	int h;
	// facade
	n = 57;
	h = 3;
	for(lcv1 = 0; lcv1 < h; ++lcv1)
	{
		push_affine_matrix(stack);
			for(lcv2 = 0; lcv2 < n; ++lcv2)
			{
				push_affine_matrix(stack);
					rotate(stack, 2 * M_PI * lcv2 / n, 0, 0, 1);
					translate(stack, 50, 0, 9 * lcv1);
					rotate(stack, -M_PI / 2, 0, 0, 1);
					place_object(&sco_file, "spr_bridge_modular_a", stack);
				pop_affine_matrix(stack);
			}
		pop_affine_matrix(stack);
	}
	// walls
	n = 19;
	for(lcv1 = 0; lcv1 < n; ++lcv1)
	{
		push_affine_matrix(stack);
			rotate(stack, 2 * M_PI * lcv1 / n, 0, 0, 1);
			for(lcv2 = 0; lcv2 < 3; ++lcv2)
			{
				push_affine_matrix(stack);
					translate(stack, 49 - 8 * lcv2, 0, 19 - 6.4 * lcv2);
					rotate(stack, -M_PI / 2, 0, 0, 1);
					rotate(stack, M_PI / 2, 1, 0, 0);
					scale(stack, (49 - 8 * lcv2) / 100.0f, 0.5, 0.5);
					place_object(&sco_file, "spr_arena_wall_a", stack);
				pop_affine_matrix(stack);
				if(lcv2 == 2)
				{
					push_affine_matrix(stack);
						translate(stack, 32.5, 5.5, 10.77);
						scale(stack, 5, 5, 4);
						place_object(&sco_file, "spr_barrier_capsule", stack);
					pop_affine_matrix(stack);
				}
				if(lcv1 == 0 && lcv2 == 2)
					continue;
				push_affine_matrix(stack);
					translate(stack, 46 - 8 * lcv2, 0, 19 - 6.4 * lcv2);
					rotate(stack, -M_PI / 2, 0, 0, 1);
					scale(stack, 2, 1, 1);
					place_object(&sco_file, "spr_stairs_a", stack);
				pop_affine_matrix(stack);
				push_affine_matrix(stack);
					translate(stack, 50 - 8 * lcv2, 0, 20 - 6.4 * lcv2);
					rotate(stack, -M_PI / 2, 0, 0, 1);
					scale(stack, (50 - 8 * lcv2) / 100.0f, 0.5, 0.4);
					place_object(&sco_file, "spr_arena_wall_a", stack);
				pop_affine_matrix(stack);
			}
			if(lcv1 == 0)
				continue;
			for(lcv2 = 0; lcv2 < 2; ++lcv2)
			{
				push_affine_matrix(stack);
					translate(stack, 34, 0, 0.8 - 6.4 * lcv2);
					rotate(stack, -M_PI / 2, 0, 0, 1);
					scale(stack, 0.34, 0.5, 0.4);
					place_object(&sco_file, "spr_arena_wall_a", stack);
				pop_affine_matrix(stack);
			}
		pop_affine_matrix(stack);
	}
	// inner ring
	n = 12;
	for(lcv1 = 0; lcv1 < n; ++lcv1)
	{
		push_affine_matrix(stack);
			rotate(stack, 2 * M_PI * lcv1 / n, 0, 0, 1);
			translate(stack, 24, 0, 0);
			rotate(stack, -M_PI / 2, 0, 0, 1);
			place_object(&sco_file, "spr_arena_barrier_b", stack);
			translate(stack, 3, 0, 6.27);
			place_object(&sco_file, "spr_castle_f_wall_way_a", stack);
			translate(stack, -6, 0, 0);
			place_object(&sco_file, "spr_castle_f_wall_way_a", stack);
		pop_affine_matrix(stack);
		push_affine_matrix(stack);
			rotate(stack, 2 * M_PI * lcv1 / n, 0, 0, 1);
			translate(stack, 29, 0, 0);
			rotate(stack, -M_PI / 2, 0, 0, 1);
			place_object(&sco_file, "spr_arabian_wall_b", stack);
		pop_affine_matrix(stack);
	}
	// stairs
	push_affine_matrix(stack);
		translate(stack, 37.5, 5, -2);
		for(lcv1 = 0; lcv1 < 5; ++lcv1)
		{
			push_affine_matrix(stack);
				translate(stack, 0, -2.5 * lcv1, 0);
				rotate(stack, M_PI, 0, 0, 1);
				place_object(&sco_file, "spr_arabian_castle_stairs", stack);
			pop_affine_matrix(stack);
		}
	pop_affine_matrix(stack);

	affine_free(stack);

	printf("Writing %s\n", argv[2]);
	write_sco_file(out, &sco_file);

	return EXIT_SUCCESS;
}
Jousting lanes -
8F0B94CC1509CF7755999048C7BBB4F00FBEEAA4
Code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "scoReader.h"
#include "scoWriter.h"
#include "affine.h"

int main(int argc, char **argv)
{
	if(argc < 3)
	{
		printf("Usage: %s input heightmap output\n", argv[0]);
		return EXIT_FAILURE;
	}

	FILE *in = fopen(argv[1], "rb");
	FILE *out = fopen(argv[2], "wb");

	if(!in || !out)
	{
		printf("ERROR: file(s) not found\n");
		return EXIT_FAILURE;
	}

	printf("Reading %s\n", argv[1]);
	sco_file_t sco_file;
	read_sco_file(in, &sco_file);

	stack_t *stack = affine_init();

	int w = 4;
	int l = 9;
	int lcv1, lcv2;
	translate(stack, 40, 130, 3.1);
	rotate(stack, (90 - 77) * M_PI / 180, 0, 0, 1);
	rotate(stack, asin(1.2 / (8 * l)), 1, 0, 0);
	// width
	push_affine_matrix(stack);
		translate(stack, 4, 0, 0);
		for(lcv1 = 0; lcv1 < w; ++lcv1)
		{
			for(lcv2 = 0; lcv2 < 2; ++lcv2)
			{
				push_affine_matrix(stack);
					translate(stack, 8 * lcv1, 8 * l * lcv2, 0);
					place_object(&sco_file, "spr_railing_a", stack);
				pop_affine_matrix(stack);
			}
		}
	pop_affine_matrix(stack);
	// length
	push_affine_matrix(stack);
		translate(stack, 0, 4, 0);
		for(lcv1 = 0; lcv1 < l; ++lcv1)
		{
			for(lcv2 = 0; lcv2 < 2; ++lcv2)
			{
				push_affine_matrix(stack);
					translate(stack, 8 * w * lcv2, 8 * lcv1, 0);
					rotate(stack, M_PI / 2, 0, 0, 1);
					place_object(&sco_file, "spr_railing_a", stack);
				pop_affine_matrix(stack);
			}
		}
		for(lcv1 = 0; lcv1 < w - 1; ++lcv1)
		{
			for(lcv2 = 0; lcv2 < l - 2; ++lcv2)
			{
				push_affine_matrix(stack);
					translate(stack, 8 * (lcv1 + 1), 8 * (lcv2 + 1), 0);
					rotate(stack, M_PI / 2, 0, 0, 1);
					place_object(&sco_file, "spr_railing_a", stack);
				pop_affine_matrix(stack);
			}
		}
	pop_affine_matrix(stack);

	affine_free(stack);

	printf("Writing %s\n", argv[2]);
	write_sco_file(out, &sco_file);

	return EXIT_SUCCESS;
}
 
Code:
*Raises eyebrows*

Let's recap: soo, you've made a extremely detailed procedurally generated coliseum using your own wrapper around scoUtils in a way we can easily make all kinds of great creations, something that wasn't even proposed in the six years of existence of Mount&Blade. And you are asking for help with 3D math.

I sincerely doubt I can help you there, mate. Let me know if you need CSS for the manual :smile:


Small digression: Somebody should tell Marco (mtarini) about this, it would be great to have map editing capabilities within OpenBRF.

Imagine, the app already mimics the game's asset loading, parses the text files, displays well most part of the shaders. We can already walk in first person using the appropriate camera mode, there are only a few parts missing, implement the
Code:
TerrainGen
class, add the
Code:
scoUtils
, some menus, implement a gizmo-like object handling in the 3D view, and some logic behind all that.

Bingo. You've a realtime usable scene editor and a handy previewer out of the game.
 
Yeah, that's kind of what I've been thinking, too.  And it would eat a lot less RAM than doing it in the in-game editor.  The only wrinkle is that auto-generated flora wouldn't be displayed, but that's very minor edits.  If it could manipulate the AI mesh, which has got to have a pretty simple data structure... well, that would sure beat working for 45 minutes on a Scene only to have the engine crash, which has happened to me more than once...

The procedural stuff is really great; I think it's necessary to test performance for that stuff vs. single meshes, though.  But an auto-city generator that laid out a set of buildings from a text file list of Scene Props or BRFs, for example... that would be a power tool!
 
xenoargh said:
Yeah, that's kind of what I've been thinking, too.  And it would eat a lot less RAM than doing it in the in-game editor.  The only wrinkle is that auto-generated flora wouldn't be displayed, but that's very minor edits.  If it could manipulate the AI mesh, which has got to have a pretty simple data structure... well, that would sure beat working for 45 minutes on a Scene only to have the engine crash, which has happened to me more than once...

I was thinking more about using Recast for generating the navigation mesh for us:
Code:
http://code.google.com/p/recastnavigation/

You know, having a pretty optimized AI mesh in seconds for every scene in your module.
Does it sound tempting enough?
 
:lol: Thanks for the kind words, Swyter, but I'm still ignorant about a lot of the gory, projective space details. Specifically, I was trying to transform the stairs in the colosseum example into more of a trapazoidal shape so they would fit without gaps. As it stands, I just plugged the holes with barriers. :neutral:



xenoargh, I agree, performance might suffer if we get too overzealous with objects. I haven't looked into generating BRFs that much because I don't know if we can add them to existing mods (which is what I'm interested in)? Also, that Recast sounds very close to what you were looking for with the AI mesh stuff! If I have some free time I might try to dive into mtarini's BRF domain and see how Recast might fit into all this.
 
The main issue with objects is that collision detection involves a fair amount of brute-force checks; the engine handles fairly large numbers of static objects pretty well but it is a concern.  If the NW patch really deals with the LOD4 issue (sorry that may be a needlessly opaque digression) then one of the major performance issues with city battle scenes (namely, overdraw) is removed, and it's down to pathfinder costs and collision objects.  Can't do anything about the former, which is already fairly efficient, if a bit, er, dumb, but the latter remains an issue that hasn't really been experimented with a lot, in terms of testing real-world impact with a bunch of Agents and missiles flying around.
 
In case anyone is interested, I made a .sco to .obj converter. It's only a first attempt, but I thought I'd share anyway :smile:

Code:
#include <stdio.h>
#include <stdlib.h>
#include "scoReader.h"
#include "scoWriter.h"
#include "sco.h"



#define mt_scene_prop 	 0
#define mt_entry_point 	 1
#define mt_scene_item 	 2
#define mt_flora 		 4
#define mt_passage 		 5

typedef struct face
{
	int v1;
	int v2;
	int v3;
} face_t;

int write_obj(char* file_name, vector_t *vertex_positions, int number_of_vertices, face_t *facelist, int number_of_faces)
{
	FILE *file = fopen ( file_name , "wt" );
	if (file==NULL)
	{
		printf("ERROR: file %s could not be opened.\n", file_name);
		return EXIT_FAILURE;
	}
	int n;
	for(n = 0; n<number_of_vertices; ++n)
	{
		fprintf(file, "v ");
		fprintf(file, "%f ", vertex_positions->x);
		fprintf(file, "%f ", vertex_positions->y);
		fprintf(file, "%f ", vertex_positions->z);
		fprintf(file, "\n");
		++vertex_positions;
	}
	for(n = 0; n<number_of_faces;++n)
	{
		fprintf(file, "f ");
		fprintf(file, "%i ", facelist->v1);
		fprintf(file, "%i ", facelist->v2);
		fprintf(file, "%i ", facelist->v3);
		fprintf(file, "\n");
		++facelist;
	}
	if(fclose(file))
	{
		printf("ERROR: file %s could not be closed.\n", file_name);
		return EXIT_FAILURE;
	}
	else
		return EXIT_SUCCESS;
}

int fill_facelist(face_t * facelist, int size_x, int size_y)
{
	face_t *face = facelist;
	int x,y;
	for (x=1; x < size_x; ++x)
	{
		for (y = 1; y < size_y; ++y)
		{
			face->v1 = y+((x-1)*size_y);
			face->v2 = y+1+((x-1)*size_y);
			face->v3 = y+(x*size_y);
			++face;
			face->v1 = y+1+((x-1)*size_y);
			face->v2 = y+1+(x*size_y);
			face->v3 = y+(x*size_y);
			++face;
		}
	}
	return EXIT_SUCCESS;
}

int main(int argc, char **argv)
{
	if(argc < 3)
	{
		printf("Usage: %s file_in file_out\n", argv[0]);
		return EXIT_FAILURE;
	}

	FILE *in = fopen(argv[1], "rb");

	if(!in)
	{
		printf("ERROR: file %s not found\n", argv[1]);
		return EXIT_FAILURE;
	}

	printf("Reading %s\n", argv[1]);
	sco_file_t sco_file;
	read_sco_file(in, &sco_file);

	vector_t *vertex_positions = malloc(sco_file.ground_paint->size_x*sco_file.ground_paint->size_y*sizeof(vector_t));
	vector_t *positions = vertex_positions;

	int layer, x, y;
	for (layer=0; layer < sco_file.ground_paint->num_layers; ++layer)
	{
		if( sco_file.ground_paint->layers[layer].ground_spec_no == GROUND_PAINT_ELEVATION_MAGIC/*GROUND_PAINT_LEVELING_MAGIC*/  && sco_file.ground_paint->layers[layer].cells!=NULL)
		{
			for( x = 0; x < sco_file.ground_paint->size_x; ++x)
			{
				for ( y = 0; y < sco_file.ground_paint->size_y; ++y)
				{
					positions->x = x;
					positions->y = y;
					positions->z = sco_file.ground_paint->layers[layer].cells[y+x*sco_file.ground_paint->size_y];
					++positions;
				}

			}
		}

	}

	int number_of_faces;
	if (sco_file.ground_paint->size_x>0 && sco_file.ground_paint->size_y>0)
	{
		number_of_faces = (sco_file.ground_paint->size_x-1)*(sco_file.ground_paint->size_y-1)*2;
	}
	else
		return EXIT_FAILURE;

	face_t *facelist = malloc((number_of_faces)*sizeof(face_t));
	if(!facelist)
		return EXIT_FAILURE;

	fill_facelist(facelist, sco_file.ground_paint->size_x, sco_file.ground_paint->size_y);

	printf("Writing %s\n", argv[2]);

	if(!write_obj(argv[2], vertex_positions, positions-vertex_positions, facelist, number_of_faces))
	{
		printf("Succesfully written to obj file.");
		return EXIT_SUCCESS;
	}
	else
		return EXIT_FAILURE;
}

[spoiler = Nevermind, fixed it! :smile:]
I've been trying to make a correct 3d mesh for the terrain using the terrain-key and sco file as inputs. However, the sco code is in c which fails to compile in visual studio and the terrain-key code is in c++ which fails to compile in my MinGW setup. I mainly have problems with the GNU compiler complaining about multiple definitions of functions in Utils.h. I sort of understands why, because it compiles all the object (.o) files seperately and then tries to put them together to make an executable. And all these object files have definitions of these fuctions. But how the hell do you fix this? It's driving me nuts.[/spoiler]
 
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.

This doesn't work in the current implementation. I'm not exactly sure why not, but an easy fix is using an union with a float and unsigned int and detect when to assign the integer.
 
It's no secret!  :grin: I just forgot to use version control so I do not know what went wrong yesterday. I got it working now without union stuff :smile: I guess I didn't cast it correctly yesterday or so.... who knows what I did at night  :lol:

I was wondering, does the random terrain generation from a terrainkey also contain vertex painting? I can't quite find it in the code, but I would think it should be in there somewhere.

So far I can write out the terrain mesh with the normals (not sure if they're working right) and the vertex colors from the sco file.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
extern "C" {
#include "scoReader.h"
#include "scoWriter.h"
#include "sco.h"
}
#include "TerrainGenerator.h"

#define mt_scene_prop 	 0
#define mt_entry_point 	 1
#define mt_scene_item 	 2
#define mt_flora 		 4
#define mt_passage 		 5


int write_ply(char* file_name, TerrainGenerator* terrainGen, sco_file_t* sco_file, char* file_in_name)
{
	FILE *file = fopen ( file_name , "wt" );
	if (file==NULL)
	{
		printf("ERROR: file %s could not be opened.\n", file_name);
		return EXIT_FAILURE;
	}

	fprintf(file, "ply\n");
	fprintf(file, "format ascii 1.0\n");
	fprintf(file, "comment This file contains the terrain mesh of %s\n", file_in_name);
	fprintf(file, "element vertex %i\n", (terrainGen->m_numFaces[0]+1)*(terrainGen->m_numFaces[1]+1) );
	fprintf(file, "property float x\n");
	fprintf(file, "property float y\n");
	fprintf(file, "property float z\n");
	fprintf(file, "property float nx\n");
	fprintf(file, "property float ny\n");
	fprintf(file, "property float nz\n");

	int layer;
	for (layer=0; layer < sco_file->ground_paint->num_layers; ++layer)
	{
		if( sco_file->ground_paint->layers[layer].ground_spec_no == GROUND_PAINT_LEVELING_MAGIC  && sco_file->ground_paint->layers[layer].cells!=NULL)
		{
			fprintf(file, "property uchar alpha\n");
			fprintf(file, "property uchar red\n");
			fprintf(file, "property uchar green\n");
			fprintf(file, "property uchar blue \n");
			break;
		}
	}

	fprintf(file, "element face %i\n", terrainGen->m_numFaces[0]*terrainGen->m_numFaces[1]*2);
	fprintf(file, "property list uchar int vertex_index\n");
	fprintf(file, "end_header\n");

	TerrainVertex vertex;
	unsigned int colorint, nx, ny;
	unsigned char alpha, red, green, blue;
	for(nx = 0; nx < terrainGen->m_numFaces[0]+1; ++nx)
	{
		for(ny =0; ny < terrainGen->m_numFaces[1]+1; ++ny)
		{
			vertex = terrainGen->m_vertices[nx][ny];
			fprintf(file, "%f %f %f ", vertex.m_position.x,vertex.m_position.y,vertex.m_position.z);
			fprintf(file, "%f %f %f ", vertex.m_normal.x,vertex.m_normal.y,vertex.m_normal.z);
			if(layer!=sco_file->ground_paint->num_layers)
			{
				colorint = *(  (unsigned int*) &(sco_file->ground_paint->layers[layer].cells[ny+nx*sco_file->ground_paint->size_y]) );
				alpha = (colorint & 0xFF000000) >> 24;
				red =   (colorint & 0x00FF0000) >> 16;
				green = (colorint & 0x0000FF00) >> 8;
				blue =  (colorint & 0x000000FF) ;
				fprintf(file, "%u %u %u %u ",alpha, red , green , blue ) ;
			}
			fprintf(file, "\n");
		}
	}
	int vertices[3][2];
	for(nx = 0; nx < terrainGen->m_numFaces[0]; ++nx)
	{
		for(ny =0; ny < terrainGen->m_numFaces[1]; ++ny)
		{
			fprintf(file, "3 ");
			terrainGen->getVerticesForFace(nx,ny,0,vertices[0],vertices[1],vertices[2]);
			fprintf(file, "%i ", vertices[0][0]*(terrainGen->m_numFaces[1]+1)+vertices[0][1]);
			fprintf(file, "%i ", vertices[1][0]*(terrainGen->m_numFaces[1]+1)+vertices[1][1]);
			fprintf(file, "%i ", vertices[2][0]*(terrainGen->m_numFaces[1]+1)+vertices[2][1]);
			fprintf(file, "\n");

			fprintf(file, "3 ");
			terrainGen->getVerticesForFace(nx,ny,1,vertices[0],vertices[1],vertices[2]);
			fprintf(file, "%i ", vertices[0][0]*(terrainGen->m_numFaces[1]+1)+vertices[0][1]);
			fprintf(file, "%i ", vertices[1][0]*(terrainGen->m_numFaces[1]+1)+vertices[1][1]);
			fprintf(file, "%i ", vertices[2][0]*(terrainGen->m_numFaces[1]+1)+vertices[2][1]);
			fprintf(file, "\n");
		}
	}
	if(fclose(file))
	{
		printf("ERROR: file %s could not be closed.\n", file_name);
		return EXIT_FAILURE;
	}
	else
		return EXIT_SUCCESS;
}

int write_obj(char* file_name, TerrainGenerator* terrainGen)
{
	FILE *file = fopen ( file_name , "wt" );
	if (file==NULL)
	{
		printf("ERROR: file %s could not be opened.\n", file_name);
		return EXIT_FAILURE;
	}
	int nx, ny;
	for(nx = 0; nx < terrainGen->m_numFaces[0]+1; ++nx)
	{
		for(ny =0; ny < terrainGen->m_numFaces[1]+1; ++ny)
		{
			fprintf(file, "v ");
			fprintf(file, "%f ", terrainGen->m_vertices[nx][ny].m_position.x);
			fprintf(file, "%f ", terrainGen->m_vertices[nx][ny].m_position.y);
			fprintf(file, "%f ", terrainGen->m_vertices[nx][ny].m_position.z);
			fprintf(file, "\n");
		}
	}
	int vertices[3][2];
	for(nx = 0; nx < terrainGen->m_numFaces[0]; ++nx)
	{
		for(ny =0; ny < terrainGen->m_numFaces[1]; ++ny)
		{

			terrainGen->getVerticesForFace(nx,ny,0,vertices[0],vertices[1],vertices[2]);
			fprintf(file, "f ");
			fprintf(file, "%i ", 1+vertices[0][0]*(terrainGen->m_numFaces[1]+1)+vertices[0][1]);
			fprintf(file, "%i ", 1+vertices[1][0]*(terrainGen->m_numFaces[1]+1)+vertices[1][1]);
			fprintf(file, "%i ", 1+vertices[2][0]*(terrainGen->m_numFaces[1]+1)+vertices[2][1]);
			fprintf(file, "\n");
			terrainGen->getVerticesForFace(nx,ny,1,vertices[0],vertices[1],vertices[2]);
			fprintf(file, "f ");
			fprintf(file, "%i ", 1+vertices[0][0]*(terrainGen->m_numFaces[1]+1)+vertices[0][1]);
			fprintf(file, "%i ", 1+vertices[1][0]*(terrainGen->m_numFaces[1]+1)+vertices[1][1]);
			fprintf(file, "%i ", 1+vertices[2][0]*(terrainGen->m_numFaces[1]+1)+vertices[2][1]);
			fprintf(file, "\n");
		}
	}
	if(fclose(file))
	{
		printf("ERROR: file %s could not be closed.\n", file_name);
		return EXIT_FAILURE;
	}
	else
		return EXIT_SUCCESS;
}


int main(int argc, char **argv)
{
	if(argc != 4)
	{
		printf("Usage: %s file_in hex_terrain_code file_out\n", argv[0]);
		return EXIT_FAILURE;
	}

	FILE *in = fopen(argv[1], "rb");

	if(!in)
	{
		printf("ERROR: file %s not found\n", argv[1]);
		return EXIT_FAILURE;
	}
	printf("Reading %s\n", argv[1]);
	sco_file_t sco_file;
	read_sco_file(in, &sco_file);

	TerrainGenerator *terrainGen; // too big for stack
	try
	{
		terrainGen = new TerrainGenerator();
		terrainGen->setTerrainCode(argv[2]);
		terrainGen->generate();
	}
	catch (...) // just for SEH, needs /EHa
	{
		printf("exception while generating terrain. check your input mang :[\n");
		system("pause");
		return EXIT_FAILURE;
	}

	if(sco_file.ground_paint->size_x-1 !=  terrainGen->m_numFaces[0] || sco_file.ground_paint->size_y-1 != terrainGen->m_numFaces[1])
	{
		printf("The terrainkey and sco don't have the same terrain size, aborting!\n");
		return EXIT_FAILURE;
	}

	int layer, x, y;
	for (layer=0; layer < sco_file.ground_paint->num_layers; ++layer)
	{
		if( sco_file.ground_paint->layers[layer].ground_spec_no == GROUND_PAINT_ELEVATION_MAGIC && sco_file.ground_paint->layers[layer].cells!=NULL)
		{
			for( x = 0; x < sco_file.ground_paint->size_x; ++x)
			{
				for ( y = 0; y < sco_file.ground_paint->size_y; ++y)
				{
					TerrainVertex *vtx = &terrainGen->m_vertices[x][y];

					vtx->m_position.z += sco_file.ground_paint->layers[layer].cells[y+x*sco_file.ground_paint->size_y];
				}

			}
		break;
		}

	}

	terrainGen->computeNormals();

	printf("Writing %s\n", argv[3]);

	char* ext = strrchr(argv[3], '.')+1;
	int write = -1;

	if(strcmp(ext, "obj")==0)
	{
		write = write_obj(argv[3], terrainGen);
	}
	else if (strcmp(ext, "ply")==0)
	{
		write = write_ply(argv[3], terrainGen, &sco_file, argv[1]);
	}
	else
	{
		printf("Uknown filetype!\n");
	}

	if(write==0)
	{
		printf("Succesfully written the %s file.", ext);
		return EXIT_SUCCESS;
	}

	return EXIT_FAILURE;
}
 
Barabas said:
I was wondering, does the random terrain generation from a terrainkey also contain vertex painting? I can't quite find it in the code, but I would think it should be in there somewhere.
It does, yes, but since I omitted the whole part that generates meshes it's not in the TerrainGenerator source.
 
I've got a problem that sometimes my program crashes trying to write the final sco file. I checked, it can open it fine, it just fails as soon as it tries to write the SCO_MAGIC  :sad:

I first read from the sco file and later try to overwrite it again with updated terrain info, maybe this doesn't work too well??
Code:
int convert_obj_to_sco(char* file_name_obj, char* terrain_key, char* file_name_sco)
{

	FILE *file_obj = fopen(file_name_obj, "rt");;
	if (file_obj==NULL)
	{
		printf("ERROR: file %s could not be opened.\n", file_name_obj);
		return EXIT_FAILURE;
	}
	int c = fgetc(file_obj);
	unsigned int n_vertices = 0;
	while(c != EOF && c!='f')
	{
		if(c=='v')
		{
			++n_vertices;
		}
		c = fgetc(file_obj);
	}
	printf("counted vertices %u\n", n_vertices);
	rewind(file_obj);

	vector_t *vertices = new vector_t[n_vertices];
	char temp[10];
	for(c = 0; c<n_vertices; ++c)
	{
		fscanf(file_obj, "%s", temp);
		fscanf(file_obj, "%f" , &(vertices+c)->x);
		fscanf(file_obj, "%f" , &(vertices+c)->y);
		fscanf(file_obj, "%f" , &(vertices+c)->z);
	}
	printf("exctracted vertices\n");

	sco_file_t sco_file;

	FILE *file_sco = fopen(file_name_sco, "rb");
	if(file_sco==NULL)
	{
		printf("Failed to open file %s\n", file_name_sco );
		return EXIT_FAILURE;
	}
	printf("Opened file %s with address %p\n",file_name_sco, file_sco );
	read_sco_file(file_sco, &sco_file);

	printf("Sco file loaded.\n");

	TerrainGenerator *terrainGen; // too big for stack
	try
	{
		terrainGen = new TerrainGenerator();
		terrainGen->setTerrainCode(terrain_key);
		terrainGen->generate();
	}
	catch (...) // just for SEH, needs /EHa
	{
		printf("exception while generating terrain. check your input mang :[\n");
		system("pause");
		return EXIT_FAILURE;
	}

	printf("Terrain generated.\n");

	ground_paint_t* ground_paint = sco_file.ground_paint;
	if( ground_paint->size_x != terrainGen->m_numFaces[0]+1 || ground_paint->size_y != terrainGen->m_numFaces[1]+1 )
	{
		printf("Sco object and terrain key don't match in size.\n");
		return EXIT_FAILURE;
	}

	qsort(vertices, n_vertices, sizeof(vector_t), comp_vertices);
	printf("Vertices from .obj sorted.\n");

	int l;
	for ( l = 0; l < ground_paint->num_layers; ++l)
	{
		if( ground_paint->layers[l].ground_spec_no == GROUND_PAINT_ELEVATION_MAGIC)
		{
			printf("Elevation layer found.\n");

			ground_paint->layers[l].cells = new float[ground_paint->size_x*ground_paint->size_y];
			ground_paint->layers[l].continuity_count = new int[ground_paint->size_x*ground_paint->size_y];
			printf("Ground paint size: %i, %i.\n",ground_paint->size_x, ground_paint->size_x );
			printf("New cells created.\n");
			int x, y, count = 0;
			ground_paint->layers[l].continuity_count[ground_paint->size_x*ground_paint->size_y] = 0;//ground_paint->size_x*ground_paint->size_y;
			for(x=0; x<ground_paint->size_x;++x)
			{
				for(y=0; y<ground_paint->size_y; ++y)
				{
					ground_paint->layers[l].continuity_count[count]=ground_paint->size_x*ground_paint->size_y-count-1;
					ground_paint->layers[l].cells[count] = vertices[x * ground_paint->size_y + y].z -terrainGen->m_vertices[x][y].m_position.z;
					++count;
				}
			}
		}
	}


	printf("Closed sco file.\n");
	if( (file_sco = fopen(file_name_sco, "wb"))==NULL)
	{
		printf("Failed to open %s\n",file_name_sco );
		return EXIT_FAILURE;
	}
	printf("Writing file %s with addres %p\n",file_name_sco, file_sco);
	write_sco_file(file_sco, &sco_file);

	return EXIT_FAILURE;
}

Just using the earlier posted write and read code.

EDIT:

Found the problem!
Code:
ground_paint->layers[l].continuity_count = new int[ground_paint->size_x*ground_paint->size_y];
should be
Code:
ground_paint->layers[l].continuity_count = new int[ground_paint->size_x*ground_paint->size_y+1];
 
Back
Top Bottom