#!/bin/perl -w
#####################################################################
# map2obj.pl
#	radiant .map file parser and .obj (wavefront) converter
#	2007-04-05 Copyright Werner 'hoehrer' Höhrer bill_spam2 [AT) yahoo (DOT] de
#
# Licence:
#	The content of this file is under the GNU/GPL license v2.
#	http://www.gnu.org/licenses/gpl.txt
#
#####################################################################
# usage: TODO
#####################################################################

use strict;
use warnings;

my $entity_open = 0;
my $brush_open = 0;

my $map_filename = 'condor04.map'; # Dummy, never used
my $obj_filename;
my $map = {};


############################
# Initialize the map data.
############################
sub map_init ($) {
	my ($map) = @_;
	
	# Init the material list
	$map->{materials} = {};
	$map->{materialcount} = 0;

	$map->{entities} = [];
	$map->{entitycount} = 0;
	
	# Init the brush-array
	$map->{brushes} = [];
	$map->{brushcount} = 0;
	
	# Init map filename (just for info)
	$map->{map_filename} = '';
	return $map;
}

sub brush_init ($) {
	my ($brush) = @_;

	$brush->{polygons} = [];
	$brush->{textures} = [];
	$brush->{polycount} = 0;
	
	$brush->{data} = {};
	return $brush;
}

sub entity_init ($) {
	my ($entity) = @_;

	# init entity
	$entity = {};
	$entity->{brushes} = [];
	$entity->{brushcount} = 0;
	$entity->{data} = {};
	return $entity;
}

############################
# Parse the text from the map file.
############################
my @lines;
sub map_parse ($) {
	my ($filename) = @_;

	open(MAP_INPUT, "< ".$filename) ||
		die "Failed to open mapfile '", $filename, "' .\n";

	my $entity;
	my $brush;
		
	$map->{map_filename} = $filename;
	my $line;
	while(<MAP_INPUT>) {
		next if /^\s*\/\//;	# Skip comments
		next if /^$/;	# Skip newlines
		next if /^\s*$/;	# Skip line with only whitespaces
		chomp;	# Remove trailing whitespaces
		

		if (!$brush_open) {	# just in case
			$brush = {};
		}
		if (!$entity_open) {	# just in case
			$entity = {};
		}

		$line = $_;
		#print $line;
		if ($line =~ m/\s*{\s*$/) {
			# Opening curly bracket found.
			#print "open bracket"; #debug
			if ($entity_open) {
				if (!$brush_open) {
					# Brush opening curly-bracket found.
					
					# init brush (TODO: extra function?)
					$brush_open = 1;
					$brush = brush_init($brush);
					
					# Add brush to map-tree
					push (@{$map->{brushes}}, $brush);
					$map->{brushcount}++;
					push (@{$entity->{brushes}}, $brush);
					$entity->{brushcount}++;
				} else {
					print "Bad opening bracked found: '",$line,"'";
					print "Syntax of file possibly corrupted. Abort.";
					return;
				}
			} else {
				# Entity opening curly-bracket found.
				$entity_open = 1;
				$entity = entity_init($entity);
		
				# Add brush to map-tree
				push (@{$map->{entities}}, $entity);
				$map->{entitycount}++;
			}
			next;
		} 
		
		if (($line =~ m/\s*\((.*)\)\s*\((.*)\)\s*\((.*)\)\s*([^\s]*)\s*(\d+\s*\d+\s*\d+\s*\d+\s*\d+\s*\d+\s*\d+\s*\d+)\s*$/) && $brush_open) {
			print "brush\n"; #debug
			# Found a polygon with texture.
			print "Parsing brush:", $map->{brushcount}-1,"\n";
			print "      Polygon:", $brush->{polycount},"\n";
			my @point1 = split($1);
			my @point2 = split($2);
			my @point3 = split($3);
			my $polygon = [${@point1}, ${@point2}, ${@point3}];
			push (@{$brush->{polygons}->[brush->polycount]}, $polygon);
			push (@{$brush->{textures}->[brush->polycount]}, $4); # store texture

			if (!exists($map->{materials}->{$brush->{textures}->[brush->polycount]})) {
				$map->{materials}->{$brush->{textures}->[brush->polycount]} = 1;
				$map->{materialcount}++;
			}

			$brush->{polycount}++;			
			next;
		}
		if ($line =~ m/\s*"(.*)"\s*"(.*)"\s*$/) {
			if ($brush_open) {
				# Found brush data
				# example: "origin" "416 -620 76"
				# $1 should be: origin
				# $2 should be: 416 -620 76
				$brush->{data}->{$1} = $2;
				#TODO: parse special cases for later export (like position and rotation).
				next;
			}
			if ($entity_open) {
				# Found brush data
				# example: "origin" "416 -620 76"
				# $1 should be: origin
				# $2 should be: 416 -620 76
				$entity->{data}->{$1} = $2;
				#TODO: parse special cases for later export (like position and rotation).
				next;
			}
		}
	
		if ($line =~ m/\s*}\s*$/) {
			# Closing curly bracket found
			if ($entity_open) {
				if ($brush_open) {
					$brush_open = 0;
				} else {
					# Last closing bracket found - pasring finished.
					$entity_open = 0;
				}
			} else {
				print "Badclosing bracked found, we haven't even met an opening one: '",$line,"'";
				print "Syntax of file possibly corrupted. Abort.";
				return;
			}
			next;
		} 
		
	}
} # parse

########################
# MAIN
########################

# parse commandline paarameters (md2-filenames)
if ( $#ARGV < 0 ) {
	die "Usage:\tmap2obj.pl <file.map>\n";
} elsif ( $#ARGV == 0 ) {
	$map_filename = $ARGV[0];
	print "Mapfile= \"". $map_filename, "\"\n";
}

# Generate output filename
if ($map_filename =~ m/.*\.map$/) {
	($obj_filename = $map_filename) =~ s/\.map$/\.obj/;
} else {
	$obj_filename = $map_filename.".obj";
}

$map = map_init($map);

# Open + parse map file
map_parse($map_filename);

use Data::Dumper;
print Dumper($map);

foreach my $mat  (keys %{$map->{materials}}) {
	print $mat;
}


# TODO: write obj (only types of "classname" that are supported by obj)
# TODO: write mtl
