%%%-------------------------------------------------------------------
%%% File    : auv_util.erl
%%% Author  : Dan Gudmundsson <dgud@erix.ericsson.se>
%%% Description : Algorithms for placing charts on texture.
%%%
%%% Created :  7 Nov 2002 by Bjorn Gustavsson
%%%-------------------------------------------------------------------
%%  Copyright (c) 2001-2003 Dan Gudmundsson, Bjorn Gustavsson
%%
%%  See the file "license.terms" for information on usage and redistribution
%%  of this file, and for a DISCLAIMER OF ALL WARRANTIES.
%%     $Id: auv_util.erl,v 1.6 2003/09/16 09:01:49 dgud Exp $

-module(auv_util).

-export([maxmin/1]).
-export([moveAndScale/5]).
-export([outer_edges/2,outer_edges/3]).
-export([number/1,number/2]).
-export([mark_segments/4,make_mat/1,seg_materials/0]).

-include("wings.hrl").
-include("auv.hrl").

-import(lists, [foldl/3,reverse/1,sort/1]).

moveAndScale([{Id, {X0, Y0,_}}|R], XD, YD, Scale, Acc) ->
    moveAndScale(R, XD,YD, Scale, 
		 [{Id, {X0*Scale+XD,Y0*Scale+YD,0.0}}|Acc]);
moveAndScale([],_,_,_,Acc) ->
    reverse(Acc).

maxmin([{Id, {X,Y,_}}|Rest]) ->
    maxmin(Rest, {Id, X},{Id, X},{Id, Y},{Id, Y});
maxmin([{Id, {X,Y}}|Rest]) ->
    maxmin(Rest, {Id, X},{Id, X},{Id, Y},{Id, Y}).

maxmin([],Xmin,Xmax,Ymin,Ymax) ->
    {Xmin,Xmax,Ymin,Ymax};
maxmin([{Id, {X,Y,_}}|Rest], 
       XMin={_IdX0,X0}, XMax={_IdX1,X1}, 
       YMin={_IdY0,Y0}, YMax={_IdY1,Y1}) ->
    if 	X > X1 ->
	    if Y > Y1 -> maxmin(Rest, XMin, {Id,X}, YMin, {Id,Y});
	       Y < Y0 -> maxmin(Rest, XMin, {Id,X}, {Id,Y}, YMax);
	       true ->   maxmin(Rest, XMin, {Id,X}, YMin, YMax)
	    end;
	X < X0 ->
	    if Y > Y1 -> maxmin(Rest,{Id,X}, XMax, YMin, {Id,Y});
	       Y < Y0 -> maxmin(Rest,{Id,X}, XMax, {Id,Y}, YMax);
	       true ->   maxmin(Rest,{Id,X}, XMax, YMin, YMax)
	    end;
	Y > Y1 ->
	    maxmin(Rest,XMin, XMax, YMin, {Id,Y});
	Y < Y0 ->
	    maxmin(Rest,XMin, XMax, {Id,Y}, YMax);
	true ->
	    maxmin(Rest,XMin, XMax, YMin, YMax)
    end;
maxmin([{Id, {X,Y}}|Rest], 
       XMin={_IdX0,X0}, XMax={_IdX1,X1}, 
       YMin={_IdY0,Y0}, YMax={_IdY1,Y1}) ->
    if 	X > X1 ->
	    if Y > Y1 -> maxmin(Rest, XMin, {Id,X}, YMin, {Id,Y});
	       Y < Y0 -> maxmin(Rest, XMin, {Id,X}, {Id,Y}, YMax);
	       true ->   maxmin(Rest, XMin, {Id,X}, YMin, YMax)
	    end;
	X < X0 ->
	    if Y > Y1 -> maxmin(Rest,{Id,X}, XMax, YMin, {Id,Y});
	       Y < Y0 -> maxmin(Rest,{Id,X}, XMax, {Id,Y}, YMax);
	       true ->   maxmin(Rest,{Id,X}, XMax, YMin, YMax)
	    end;
	Y > Y1 ->
	    maxmin(Rest,XMin, XMax, YMin, {Id,Y});
	Y < Y0 ->
	    maxmin(Rest,XMin, XMax, {Id,Y}, YMax);
	true ->
	    maxmin(Rest,XMin, XMax, YMin, YMax)
    end.

outer_edges(Faces0, We) ->
    outer_edges(Faces0, We, true).
outer_edges(Faces0, We, VisibleOnly) ->    
    %% I use normals here to detect direction of face and remove 
    %% faces with wrong direction.
    Faces1 = case VisibleOnly of 
		 true ->
		     foldl(fun(Face, Acc)-> 
				   Zval = e3d_vec:dot(wings_face:normal(Face, We), 
						      {0.0,0.0,1.0}),
				   case Zval >= 0.0 of
				       true -> [Face|Acc];
				       _ -> Acc
				   end
			   end, [], Faces0);
		 false ->
		     Faces0
	     end,
    S = wings_face:fold_faces(fun(Face, _, E, _, A) -> [{E,Face}|A] end, [], Faces1, We),
    outer_edges_1(sort(S), []).
outer_edges_1([{E,_},{E,_}|T], Out) ->
    outer_edges_1(T, Out);
outer_edges_1([E|T], Out) ->
    outer_edges_1(T, [E|Out]);
outer_edges_1([], Out) -> reverse(Out).

number(L) ->
    ?MODULE:number(L,0).
number([H|T], N) ->
    [{N,H}|number(T, N+1)];
number([], _) -> [].


mark_segments(Charts, Cuts, We0, St) ->
    We = We0#we{he=Cuts},			%Hard edges mark the cuts.

    %% Use materials to mark different charts.
    Template = list_to_tuple([auv_util:make_mat(Diff) || {_,Diff} <- seg_materials()]),
    assign_materials(Charts, We, Template, 0, St).

assign_materials([Faces|T], We0, Template, I0, #st{mat=Mat0}=St0) ->
    I = I0 + 1,
    MatName = list_to_atom("AuvChart" ++ integer_to_list(I)),
    We = wings_material:assign(MatName, Faces, We0),
    case gb_trees:is_defined(MatName, Mat0) of
	true ->
	    assign_materials(T, We, Template, I, St0);
	false ->
	    MatDef = element(I0 rem size(Template) + 1, Template),
	    {St,[]} = wings_material:add_materials([{MatName,MatDef}], St0),
	    assign_materials(T, We, Template, I, St)
    end;
assign_materials([], #we{id=Id}=We, _, _, #st{shapes=Shs0}=St) ->
    Shs = gb_trees:update(Id, We, Shs0),
    St#st{shapes=Shs}.

make_mat(Diff) ->
    [{opengl,[{diffuse,Diff},
	      {ambient,Diff},
	      {specular,{0.0,0.0,0.0}}]}].

seg_materials() -> % Intensity 0.7 for all
    [{'AuvChart1',{0.7,0.7,0.0}},  % Yellow
     {'AuvChart2',{0.0,0.7,0.7}},  % Cyan
     {'AuvChart3',{0.7,0.0,0.7}},  % Magenta
     separator,
     {'AuvChart4',{0.4,0.7,0.0}},  % Yellow -> Green
     {'AuvChart5',{0.0,0.4,0.7}},  % Cyan -> Blue
     {'AuvChart6',{0.7,0.0,0.4}},  % Magenta -> Red
     separator,
     {'AuvChart7',{0.0,0.7,0.4}},  % Cyan -> Green
     {'AuvChart8',{0.4,0.0,0.7}},  % Magenta -> Blue
     {'AuvChart9',{0.7,0.4,0.0}},
     {?HOLE,      {0.0,0.0,0.9}}]. % _Hole_
