Skip to content

Commit

Permalink
NOTE: In the Tools menu, Snap Image and Screenshot have been extended
Browse files Browse the repository at this point in the history
in several useful ways. It is now possible to take a screenshot of
just the main viewport. Coupled with this feature are changes to
Snap Image, which now has options to Fit the image to the viewport's
dimensions. This new combination of features allows for better
projection painting workflows using a 2d painting program like Gimp.
The new Screenshot features are available through in its options
dialog. You can also save the current view to the Saved Views at
the same time and with the same name as the screenshot so that they
can be aligned later. Additionally, one can now scale the snap image
proportionally to its current x or y value, or reset the snap image
to its actual size. Also, when exporting or making an image external
from the Outliner, the image name will automatically update in the
Outliner to the filename you save it as. [optigon]
  • Loading branch information
Richard Jones authored and Richard Jones committed Sep 18, 2010
1 parent 523822b commit 9644e36
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 39 deletions.
105 changes: 76 additions & 29 deletions plugins_src/autouv/wpc_snap.erl
Expand Up @@ -46,36 +46,56 @@ menu({face}, Menu) ->
[{?__(5,"Snap Image"),snap_image,
?__(6,"Put background image on selected faces by assigning "
"UV coordinates to them")}|
snap_menu()] ++ Menu
snap_menu()] ++ Menu
end;
menu({Type}, Menu) when Type == vertex; Type == edge;
Type == body; Type == shape ->
case active() of
false -> Menu;
true -> snap_menu() ++ Menu
true -> snap_menu() ++ Menu
end;
menu(_, Menu) -> Menu.

snap_menu() ->
ScaleMenu = [{?__(1,"Horizontal"),x,?__(2,"Scale the background image horizontally")},
{?__(3,"Vertical"),y,?__(4,"Scale the background image vertically")},
{?__(5,"Free"),free,?__(6,"Scale the background image freely")},
{?__(7,"Uniform"),uniform,?__(8,"Scale the background image uniformly")}],
MoveMenu = [{?__(9,"Horizontal"),x,?__(10,"Move the background image horizontally")},
{?__(11,"Vertical"),y, ?__(12,"Move the background image vertically")},
{?__(13,"Free"),free, ?__(14,"Move the background image freely")}],
{?__(7,"Uniform"),uniform,?__(8,"Scale the background image uniformly")},
{?__(32,"Proportional"),{auv_snap_prop,proportional_scale()},?__(33,"Make image scale proportional")}],
MoveMenu = [{?__(1,"Horizontal"),x,?__(10,"Move the background image horizontally")},
{?__(3,"Vertical"),y, ?__(12,"Move the background image vertically")},
{?__(5,"Free"),free, ?__(14,"Move the background image freely")},
separator,
{?__(30,"Center"),center, ?__(31,"Center the background image to the viewport")},
{?__(26,"Center X"),center_x, ?__(27,"Center the background image horizontally")},
{?__(28,"Center Y"),center_y, ?__(29,"Center the background image vertically")}],

[{?__(15,"Scale Snap Image"),{auv_snap_scale,ScaleMenu},?__(16,"Scale the background image")},
{?__(17,"Move Snap Image"),{auv_snap_move,MoveMenu},?__(18,"Move the background image")},
{?__(21,"Fit Snap Image"),{auv_snap_fit,
[{?__(22,"Both"),both},
{?__(1,"Horizontal"),x},
{?__(3,"Vertical"),y}]},
?__(25,"Fit image to the dimensions of the viewport")},
{?__(19,"Exit Snap Mode"),exit_snap_mode,?__(20,"Exit the snap mode")},
separator].

proportional_scale() ->
[{?__(1,"...to Current X"),proportional_x,
?__(2,"Scale image's Y value to be proportional to it's current X value")},
{?__(3,"...to Current Y"),proportional_y,
?__(4,"Scale image's X value to be proportional to it's current Y value")},
{?__(5,"Actual Size"),actual_size,
?__(6,"Reset image to its actual size")}].

command({face,snap_image}, St) ->
snap(St);
command({_,{auv_snap_scale,Op}}, St) ->
scale(Op,St);
command({_,{auv_snap_move,Op}}, St) ->
move(Op,St);
command({_,{auv_snap_fit,Op}}, St) ->
fit(Op,St);
command({tools,snap_image_mode}, St) ->
select_image(St);
command({_,exit_snap_mode}, St) ->
Expand Down Expand Up @@ -116,25 +136,33 @@ select_image(_St) ->
end.

find_images() ->
case wings_image:images() of
case wings_image:images() of
[] -> [];
Imgs = [{Def,_}|_] -> find_images_1(Imgs, Def, 0)
end.

find_images_1([{Id,#e3d_image{name=Name}}|Tail], Def, Key) ->
[{key_alt,{Key,Def},Name,Id}|find_images_1(Tail, Def, Key-1)];
find_images_1([], _Def, _Key) -> [].


scale({auv_snap_prop,Proportional}, St) ->
State = #s{sx=Ix,sy=Iy} = get(?MODULE),
case Proportional of
proportional_x -> put(?MODULE, State#s{sy=Ix});
proportional_y -> put(?MODULE, State#s{sx=Iy});
actual_size -> put(?MODULE, State#s{sx=1.0,sy=1.0})
end,
St;
scale(Op, St) ->
#s{sx=Ix,sy=Iy} = get(?MODULE),
ScaleFun = fun({finish,_}, Dlo) -> Dlo;
([X,Y], Dlo) ->
([X,Y], Dlo) ->
State = #s{sx=SX,sy=SY} = get(?MODULE),
case Op of
case Op of
x -> put(?MODULE, State#s{sx=X});
y -> put(?MODULE, State#s{sy=Y});
free -> put(?MODULE, State#s{sx=X,sy=Y});
uniform ->
uniform ->
Diff = X-SX,
DY = SY+Diff,
put(?MODULE, State#s{sx=X,sy=DY})
Expand All @@ -146,43 +174,62 @@ scale(Op, St) ->
Flags = [{initial, [Ix,Iy]}],
wings_drag:setup(Tvs,Units,Flags,St).

move(Op, St) when Op =:= center_x; Op =:= center_y; Op =:= center ->
S = get(?MODULE),
case Op of
center_x -> put(?MODULE, S#s{tx=0.0});
center_y -> put(?MODULE, S#s{ty=0.0});
center -> put(?MODULE, S#s{tx=0.0,ty=0.0})
end,
St;
move(Op, St) ->
#s{tx=Ix,ty=Iy} = get(?MODULE),
MoveFun = fun({finish,_}, Dlo) -> Dlo;
([X,Y], Dlo) ->
([X,Y], Dlo) ->
State = get(?MODULE),
case Op of
case Op of
x -> put(?MODULE, State#s{tx=-X});
y -> put(?MODULE, State#s{ty=-Y});
free -> put(?MODULE, State#s{tx=-X,ty=-Y})
end,
Dlo
end,

Tvs = {general, [{find_a_id(St), MoveFun}]},
Units = [{dx, {-?HUGE,?HUGE}},{dy,{-?HUGE,?HUGE}}],
Flags = [{initial, [-Ix,-Iy]}],
wings_drag:setup(Tvs,Units,Flags,St).

fit(Op, St) ->
#s{w=IW,h=IH}=S = get(?MODULE),
{_,_,W,H} = wings_wm:viewport(),
{X,Y} = scale(W,H,IW,IH),
case Op of
x -> put(?MODULE, S#s{sx=1.0/X,tx=0.0});
y -> put(?MODULE, S#s{sy=1.0/Y,ty=0.0});
both -> put(?MODULE, S#s{sx=1.0/X,sy=1.0/Y,tx=0.0,ty=0.0})
end,
St.

find_a_id(#st{shapes=Shs}) ->
Ida = [Id || #we{id=Id,perm=Perm} <- gb_trees:values(Shs),
?IS_VISIBLE(Perm)],
Id = case length(Ida) of
0 -> wpa:error(?__(1,"Visible object required."));
_ -> lists:min(Ida)
end,
end,
Id.

draw_image(Image,_St) ->
gl:pushAttrib(?GL_ALL_ATTRIB_BITS),
gl:pushAttrib(?GL_ALL_ATTRIB_BITS),
gl:matrixMode(?GL_PROJECTION),
gl:loadIdentity(),
glu:ortho2D(0.0, 1.0, 0.0, 1.0),
gl:matrixMode(?GL_MODELVIEW),
gl:loadIdentity(),

gl:disable(?GL_LIGHTING),
gl:disable(?GL_DEPTH_TEST),
gl:disable(?GL_DEPTH_TEST),
gl:disable(?GL_ALPHA_TEST),

gl:enable(?GL_BLEND),
Expand All @@ -195,7 +242,7 @@ draw_image(Image,_St) ->
gl:color4f(1.0, 1.0, 1.0, 0.55), %%Semitransparant
{_,_,W,H} = wings_wm:viewport(),
{Xs,Ys,Xe,Ye} = {0,0,1,1},

#s{w=IW,h=IH,sx=Sx,sy=Sy,tx=Tx,ty=Ty} = get(?MODULE),
{X,Y} = scale(W,H,IW,IH),

Expand All @@ -215,7 +262,7 @@ draw_image(Image,_St) ->

gl:'end'(),
gl:popAttrib().

calc_uv_fun() ->
%% First do all the view-dependent calculations that are
%% common for all vertices.
Expand All @@ -232,10 +279,10 @@ calc_uv_fun() ->
end.

scale(W, H, IW, IH) ->
if
if
W == H ->
if
IW == IH ->
if
IW == IH ->
{1,1};
IW > IH ->
{1.0,IW/IH};
Expand All @@ -247,15 +294,15 @@ scale(W, H, IW, IH) ->
{W/H, 1.0};
IH > IW ->
{W/H*IH/IW, 1.0};
true ->
true ->
{W/H,IW/IH}
end;
true ->
true ->
if IW == IH ->
{1.0, H/W};
IW > IH ->
{1.0, IW/IH*H/W};
true ->
true ->
{IH/IW,H/W}
end
end.
Expand All @@ -273,14 +320,14 @@ insert_we_uvs(Faces, CalcUV, We) ->
end, [], Faces, We),
VFaces = wings_util:rel2fam(VFace),
insert_we_uvs_1(VFaces, CalcUV, We).

insert_we_uvs_1([{V,Faces}|T], CalcUV, We0) ->
UV = CalcUV(wings_vertex:pos(V, We0)),
We = wings_va:set_vtx_face_uvs(V, Faces, UV, We0),
insert_we_uvs_1(T, CalcUV, We);
insert_we_uvs_1([], _, We) -> We.

set_materials(Image,St0) ->
set_materials(Image,St0) ->
Fix = fun(Items,We0,NewMats0) ->
Set = fun(Face,_,_,_,{We1,NMats0}) ->
FaceM = wings_facemat:face(Face, We0),
Expand All @@ -301,7 +348,7 @@ dup_mat(MatName,{Used,St0},{Image,Name}) ->
Mat0 = gb_trees:get(MatName, St0#st.mat),
Maps0 = proplists:get_value(maps, Mat0),
case proplists:get_value(diffuse, Maps0) of
Image ->
Image ->
%% It already has the texture; no need to create new material
{MatName,{[{MatName,MatName}|Used],St0}};
Else ->
Expand Down Expand Up @@ -332,4 +379,4 @@ dup_mat(MatName,{Used,St0},{Image,Name}) ->
{ChangedMatName, {[{MatName,ChangedMatName}|Used],St}}
end
end.

7 changes: 3 additions & 4 deletions src/wings.erl
Expand Up @@ -757,9 +757,8 @@ command_1({tools,{scale_bb_to_sel,Dir}}, St) ->
{save_state,wings_align:scale_bb_to_sel(Dir, St)};
command_1({tools,{virtual_mirror,Cmd}}, St) ->
wings_view:virtual_mirror(Cmd, St);
command_1({tools, screenshot}, St) ->
wings_image:screenshot(),
St;
command_1({tools, {screenshot,Ask}}, St) ->
wings_image:screenshot(Ask,St);
command_1({tools, area_volume_info}, St) ->
area_volume_info(St),
St;
Expand Down Expand Up @@ -868,7 +867,7 @@ tools_menu(_) ->
?__(23,"Create real geometry from the virtual mirrors")}]}},
separator,
{?__(24,"Screenshot"), screenshot,
?__(25,"Grab an image of the window (export it from the outliner)")},
?__(25,"Grab an image of the window (export it from the outliner)"),[option]},
separator,
{?__(26,"Scene Info: Area & Volume"), area_volume_info,
?__(27,"Calculate area and volume for each object in the scene")},
Expand Down
47 changes: 43 additions & 4 deletions src/wings_image.erl
Expand Up @@ -14,7 +14,8 @@
-module(wings_image).
-export([init/1,init_opengl/0,
from_file/1,new/2,new_temp/2,create/1,
rename/2,txid/1,info/1,images/0,screenshot/0,
rename/2,txid/1,info/1,images/0,
screenshot/2,screenshot/1,viewport_screenshot/1,
bumpid/1, default/1,
is_normalmap/1, normal_cubemapid/0, pnoiseid/0,
next_id/0,delete_older/1,delete_from/1,delete/1,
Expand Down Expand Up @@ -122,16 +123,54 @@ rename(Id, NewName) ->
txid(Id) ->
req({txid,Id}, false).

screenshot() ->
screenshot(Ask, _) when is_atom(Ask) ->
ViewPortOnly = wings_pref:get_value(screenshot_viewport_only, false),
SaveView = wings_pref:get_value(screenshot_save_current_view, false),
Qs = [{?__(2,"Capture viewport only"),ViewPortOnly},
{?__(3,"Add current view to Saved Views"),SaveView},
{hframe,[{label,?__(4,"Name")},
{text,?__(1,"Screenshot"),[]}]}],
wings_ask:dialog(Ask, ?__(1,"Screenshot"), [{vframe,Qs}],
fun(Res) ->
{tools,{screenshot,Res}}
end);
screenshot([ViewPortOnly,SaveView,Name], St) ->
wings_pref:set_value(screenshot_viewport_only, ViewPortOnly),
wings_pref:set_value(screenshot_save_current_view, SaveView),
wings_wm:send_after_redraw(geom,{action,{tools,{screenshot,[ViewPortOnly,Name]}}}),
case SaveView of
true -> wings_view:command({views,{save,[Name]}},St);
false -> St
end;
screenshot([ViewPortOnly,Name], St) ->
case ViewPortOnly of
true -> viewport_screenshot(Name);
false -> screenshot(Name)
end,
St.

screenshot(Name) ->
{W,H} = wings_wm:top_size(),
gl:pixelStorei(?GL_PACK_ALIGNMENT, 1),
gl:readBuffer(?GL_FRONT),
Mem = wings_io:get_buffer(W*H*3, ?GL_UNSIGNED_BYTE),
gl:readPixels(0, 0, W, H, ?GL_RGB, ?GL_UNSIGNED_BYTE, Mem),
ImageBin = wings_io:get_bin(Mem),
Image = #e3d_image{image=ImageBin,width=W,height=H},
Id = new_temp(?__(1,"<<Screenshot>>"), Image),
wings_image:window(Id).
Id = new_temp(Name, Image),
window(Id).

viewport_screenshot(Name) ->
%% screenshot of just the viewport scene
{X,Y,W,H} = wings_wm:viewport(),
gl:pixelStorei(?GL_PACK_ALIGNMENT, 1),
gl:readBuffer(?GL_FRONT),
Mem = wings_io:get_buffer(W*H*3, ?GL_UNSIGNED_BYTE),
gl:readPixels(X, Y, W, H, ?GL_RGB, ?GL_UNSIGNED_BYTE, Mem),
ImageBin = wings_io:get_bin(Mem),
Image = #e3d_image{image=ImageBin,width=W,height=H},
Id = new_temp(Name, Image),
window(Id).

is_normalmap(Id) ->
req({is_normalmap,Id},false).
Expand Down
17 changes: 15 additions & 2 deletions src/wings_outliner.erl
Expand Up @@ -243,7 +243,7 @@ image_menu(Id, Im) ->
image_menu_1(Id, #e3d_image{filename=none}) ->
[{?__(1,"Make External..."),menu_cmd(make_external, Id)}|common_image_menu(Id)];
image_menu_1(Id, _) ->
[{?__(2,"Refresh"),menu_cmd(refresh_image, Id)},
[{?__(2,"Refresh"),menu_cmd(refresh_image, Id),?__(11,"Update image to the contents of the saved file")},
{?__(3,"Make Internal"),menu_cmd(make_internal, Id)}|common_image_menu(Id)].

common_image_menu(Id) ->
Expand Down Expand Up @@ -371,6 +371,7 @@ make_external(Id) ->
case wings_image:image_write(Ps) of
ok ->
wings_image:update_filename(Id, Name),
rename(Id, Name),
keep;
{_,Error0} ->
Error = Name ++ ": " ++ file:format_error(Error0),
Expand Down Expand Up @@ -405,7 +406,9 @@ export_image(Id) ->
Image = wings_image:info(Id),
Ps = [{image,Image},{filename,Name}],
case wings_image:image_write(Ps) of
ok -> keep;
ok ->
rename(Id, Name),
keep;
{_,Error0} ->
Error = Name ++ ": " ++ file:format_error(Error0),
wings_u:message(Error)
Expand Down Expand Up @@ -634,3 +637,13 @@ lines(#ost{lh=Lh}) ->

title() ->
?__(1,"Outliner").

rename(Id, Name) ->
{NewName,_} = lists:splitwith(fun(Char) ->
case Char of
$\ -> false;
$/ -> false;
_ -> true
end
end, reverse(Name)),
wings_image:rename(Id, reverse(NewName)).

0 comments on commit 9644e36

Please sign in to comment.