diff --git a/plugins_src/primitives/wpc_image.erl b/plugins_src/primitives/wpc_image.erl index c54e6cbb3..5d5ead54e 100644 --- a/plugins_src/primitives/wpc_image.erl +++ b/plugins_src/primitives/wpc_image.erl @@ -275,7 +275,7 @@ load_img_plane(FileName, #e3d_image{type=Type}=Image0) -> wpa:error_msg(?__(1,"The image cannot be loaded as a texture.~nFile: \"~s\"~n GLU Error: ~p - ~s~n"), [FileName,GlErr, wings_gl:error_string(GlErr)]); Image0i -> - Image1 = e3d_image:convert(Image0i, img_type(Type), 1, lower_left), + Image1 = e3d_image:convert(Image0i, wings_image:img_type(Type), 1, lower_left), #e3d_image{width=W0,height=H0} = Image1, Image = case pad_image(Image1) of Image1 -> @@ -307,7 +307,7 @@ ratio(W, H) when W < H -> {1.0,H/W}; ratio(W, H) -> {W/H,1.0}. pad_image(#e3d_image{width=W0,image=Pixels0,bytes_pp=PP}=Image) -> - case nearest_power_two(W0) of + case wings_image:nearest_power_two(W0) of W0 -> pad_image_1(Image); W -> @@ -317,7 +317,7 @@ pad_image(#e3d_image{width=W0,image=Pixels0,bytes_pp=PP}=Image) -> end. pad_image_1(#e3d_image{width=W,height=H0,image=Pixels0,bytes_pp=PP}=Image) -> - case nearest_power_two(H0) of + case wings_image:nearest_power_two(H0) of H0 -> pad_image_2(Image); H -> @@ -345,13 +345,3 @@ zeroes(N) when N rem 2 =:= 0 -> zeroes(N) -> Z = zeroes(N div 2), [0,Z|Z]. - -nearest_power_two(N) -> - nearest_power_two(N, 1). - -nearest_power_two(N, B) when N =< B -> B; -nearest_power_two(N, B) -> nearest_power_two(N, B bsl 1). - -img_type(b8g8r8) -> r8g8b8; -img_type(b8g8r8a8) -> r8g8b8a8; -img_type(Type) -> Type. diff --git a/shaders/hemilight.fs b/shaders/hemi_light.fs similarity index 100% rename from shaders/hemilight.fs rename to shaders/hemi_light.fs diff --git a/shaders/matcap_light.fs b/shaders/matcap_light.fs new file mode 100644 index 000000000..4caca992f --- /dev/null +++ b/shaders/matcap_light.fs @@ -0,0 +1,60 @@ +// $Id$ +// +// Fragment shader for MatCap light +// +// Author: 2026 Micheus +// + +#version 120 + +#include "lib_base.glsl" +#include "lib_normal.glsl" +#include "lib_material.glsl" + + +varying vec3 vs_position; +varying vec3 vs_normal; +varying mat3 wv_matrix; + +uniform float MatCapRot; +uniform int MatCapUseDiffuse; +uniform sampler2D MatCapMap; + + +vec2 matcapUV(vec3 vec) +{ + float ofs = 2.0*sqrt(vec.x*vec.x + vec.y*vec.y + (vec.z+1.0)*(vec.z+1.0)); + vec2 uv = vec.xy/ofs+0.5; + return uv; +} + +vec3 matcapRotate(vec3 v, float a) { + float c = cos(a); + float s = sin(a); + vec3 n = vec3(0.0,0.0,1.0); + return v*c + cross(n, v)*s + n*dot(n, v)*(1.0-c); +} + +vec4 calcBasecolor(vec4 v_basecolor) { + if(MatCapUseDiffuse > 0) { + vec4 basecolor = get_basecolor(); + return v_basecolor*basecolor; + } else + return v_basecolor; +} + +void main() { + vec3 n = get_normal(); + + vec3 vN = normalize(wv_matrix * n); // convert world-space normal into view-space + vec3 vP = normalize(-vs_position); // view-space view vector (camera at origin) + vec3 r = reflect(-vP, vN); // reflection vector in view space + r = normalize(r); + + vec3 Rr = matcapRotate(r, MatCapRot); + Rr = normalize(Rr); + + vec2 uv = matcapUV(Rr); + vec4 basecolor = calcBasecolor(texture2D(MatCapMap, uv)); + gl_FragColor = vec4(basecolor.rgb, 1.0); +} \ No newline at end of file diff --git a/shaders/standard.vs b/shaders/standard.vs index edcb3f220..2ba9da794 100644 --- a/shaders/standard.vs +++ b/shaders/standard.vs @@ -12,6 +12,10 @@ varying vec4 ws_tangent; // world space varying vec3 ws_position; // world space varying vec4 v_basecolor; +varying vec3 vs_normal; // view space +varying vec3 vs_position; // view space +varying mat3 wv_matrix; + uniform mat3x4 ws_matrix; vec4 SRGBtoLINEAR(vec4 srgbIn) @@ -23,6 +27,11 @@ vec4 SRGBtoLINEAR(vec4 srgbIn) void main(void) { + vec4 viewPos4 = gl_ModelViewMatrix * gl_Vertex; + vs_position = viewPos4.xyz; + vs_normal = normalize(gl_NormalMatrix * gl_Normal); + wv_matrix = mat3(gl_ModelViewMatrix); + ws_position = mat3x3(ws_matrix)*gl_Vertex.xyz; // ws_position = gl_Vertex.xyz; v_basecolor = diffuse * SRGBtoLINEAR(gl_Color); diff --git a/src/wings.hrl b/src/wings.hrl index 29199336b..f341ea6ec 100644 --- a/src/wings.hrl +++ b/src/wings.hrl @@ -76,6 +76,7 @@ -define(ENV_DIFF_MAP_UNIT, 3). -define(ENV_SPEC_MAP_UNIT, 4). -define(ENV_BRDF_MAP_UNIT, 5). +-define(MATCAP_MAP_UNIT, 7). -define(AREA_LTC_MAT_UNIT, 8). %% %% Extra materials -define(EMISSION_MAP_UNIT, 6). diff --git a/src/wings_image.erl b/src/wings_image.erl index 3bf7af442..e6d2504e8 100644 --- a/src/wings_image.erl +++ b/src/wings_image.erl @@ -23,7 +23,7 @@ window/1, debug_display/2]). -export([image_formats/0,image_read/1,image_write/1, e3d_to_wxImage/1, wxImage_to_e3d/1, resize_image/3]). --export([maybe_exceds_opengl_caps/1]). +-export([maybe_exceds_opengl_caps/1, img_type/1, nearest_power_two/1]). -behavior(gen_server). -export([start_link/0, init/1, handle_call/3, handle_cast/2]). diff --git a/src/wings_light.erl b/src/wings_light.erl index abff2fe02..e44769be3 100644 --- a/src/wings_light.erl +++ b/src/wings_light.erl @@ -4,7 +4,7 @@ %% Implementation of lights. %% %% Copyright (c) 2002-2011 Bjorn Gustavsson -%% +%% 2026 Micheus (support to matcap) %% See the file "license.terms" for information on usage and redistribution %% of this file, and for a DISCLAIMER OF ALL WARRANTIES. %% @@ -12,7 +12,7 @@ %% -module(wings_light). --export([init/0, init/1, init_opengl/0, load_env_image/1, +-export([init/0, init/1, init_opengl/0, load_env_image/1, load_matcap_texture/1, light_types/0,menu/3,command/2,is_any_light_selected/1, any_enabled_lights/0,info/1,setup_light/2, create/2,update_dynamic/2,update_matrix/2,update/1, @@ -55,11 +55,19 @@ def_envmap() -> DefPath = filename:join(wings_util:lib_dir(wings), "textures"), filename:join(DefPath, DefEnvMap). +def_matcap() -> + DefMatCap = "LitSphere1.png", + DefPath = filename:join([wings_util:lib_dir(wings), "textures", "matcap"]), + filename:join(DefPath, DefMatCap). + init() -> wings_pref:set_default(show_bg, false), wings_pref:set_default(show_bg_blur, 0.5), wings_pref:set_default(show_bg_rotate, 0.0), wings_pref:set_default(bg_image, def_envmap()), + wings_pref:set_default(matcap_texture, def_matcap()), + wings_pref:set_default(matcap_rotate, 0.0), + wings_pref:set_default(matcap_use_diffuse, false), EnvImgRec = load_env_file(wings_pref:get_value(bg_image)), init(false, EnvImgRec). @@ -69,6 +77,7 @@ init(Recompile) -> %% Debug init(Recompile, EnvImgRec) -> AreaMatTagId = load_area_light_tab(), + MatCapTagId = load_matcap_light_tag(), EnvIds = case wings:is_fast_start() orelse cl_setup(Recompile) of true -> fake_envmap(load_env_file(def_envmap())); @@ -80,7 +89,7 @@ init(Recompile, EnvImgRec) -> CL -> make_envmap(CL, EnvImgRec) end, - [?SET(Tag, Id) || {Tag,Id} <- [AreaMatTagId|EnvIds]], + [?SET(Tag, Id) || {Tag,Id} <- [AreaMatTagId|EnvIds++MatCapTagId]], init_opengl(), wings_develop:gl_error_check({?MODULE,?FUNCTION_NAME}), ok. @@ -106,12 +115,34 @@ load_env_image_1(FileName) -> wings_develop:gl_error_check({?MODULE,?FUNCTION_NAME}), ok. +-spec load_matcap_texture(FileName::string()) -> ok | {file_error, {error, term()}}. +load_matcap_texture(FileName) -> + try load_matcap_texture_1(FileName) + catch throw:Error -> + Error + end. + +load_matcap_texture_1(FileName) -> + Img = wings_image:image_read([{filename, FileName}]), + is_record(Img, e3d_image) orelse throw({file_error, Img}), + #e3d_image{width=W,height=H}=Img, + if (W=/=H) -> throw({file_error,{error,"Image must be square and sized to a power of two"}}); + true -> ok + end, + Res = wings_image:nearest_power_two(W), + {{Tag,Id},_} = make_matcap(Img, Res), + ?SET(Tag, Id), + init_opengl(), + wings_develop:gl_error_check({?MODULE,?FUNCTION_NAME}), + ok. + init_opengl() -> %% Bind textures to units Ids = [{areamatrix_tex, ?AREA_LTC_MAT_UNIT}, {brdf_tex, ?ENV_BRDF_MAP_UNIT}, {env_diffuse_tex, ?ENV_DIFF_MAP_UNIT}, - {env_spec_tex, ?ENV_SPEC_MAP_UNIT}], + {env_spec_tex, ?ENV_SPEC_MAP_UNIT}, + {matcap_tex, ?MATCAP_MAP_UNIT}], SetupUnit = fun({Tag, Unit}) -> case ?GET(Tag) of undefined -> ignore; @@ -156,7 +187,6 @@ command({duplicate,Dir}, St) -> duplicate(Dir, St). -spec is_any_light_selected(#st{}) -> boolean(). - is_any_light_selected(St) -> MF = fun(_, We) -> ?IS_LIGHT(We) end, RF = fun erlang:'or'/2, @@ -644,7 +674,9 @@ export_camera_lights() -> [{?__(2,"Infinite"),camera_infinite_1_0()}]; 2 -> [{?__(3,"Infinite1"),camera_infinite_2_0()}, - {?__(4,"Infinite2"),camera_infinite_2_1()}] + {?__(4,"Infinite2"),camera_infinite_2_1()}]; + 3 -> + [{?__(2,"Infinite"),camera_infinite_1_0()}] end, #view{origin=Aim} = wings_view:current(), CameraPos = wings_view:eye_point(), @@ -1011,6 +1043,16 @@ load_area_light_tab() -> ?CHECK_ERROR(), {areamatrix_tex, ImId}. +load_matcap_light_tag() -> + FileName = wings_pref:get_value(matcap_texture, def_matcap()), + case load_matcap_texture(FileName) of + ok -> + Id = ?GET(matcap_tex), + [{matcap_tex,Id}]; + _ -> + [] + end. + fake_envmap(EnvImgRec) -> %% Poor mans version with blurred images Path = filename:join(wings_util:lib_dir(wings), "textures"), @@ -1120,6 +1162,13 @@ make_mipmaps(Img, _, _, _) -> wxImage:destroy(Img), []. +make_matcap(Img0, Res) -> + Opts = [{wrap, {clamp,clamp}}, {filter, {linear, linear}}], + Img = wings_image:resize_image(Img0#e3d_image{extra=Opts},Res,Res), + %% wings_image:debug_display(matcap,Img#e3d_image{name="MatCap"}), + ImId = wings_image:new_hidden(matcap_tex, Img), + {{matcap_tex, ImId}, Img#e3d_image.image}. + make_envmap(CL, #e3d_image{filename=FileName}=EnvImgRec) -> EnvIds = case load_cached_envmap(FileName) of diff --git a/src/wings_menu.erl b/src/wings_menu.erl index fa37fc46e..557e98741 100644 --- a/src/wings_menu.erl +++ b/src/wings_menu.erl @@ -15,7 +15,7 @@ -module(wings_menu). -export([is_popup_event/1,popup_menu/4,build_command/2, kill_menus/0, predefined_item/2]). --export([setup_menus/2, id_to_name/1, check_item/1, str_clean/1]). +-export([setup_menus/2, id_to_name/1, check_item/1, select_item/1, str_clean/1]). -export([update_menu/3, update_menu/4, update_menu_enabled/3, update_menu_hotkey/2]). @@ -797,6 +797,13 @@ check_item(Name) -> wxMenuItem:check(MenuItem, [{check, not Checked}]) end. +select_item(Name) -> + case ets:match_object(wings_menus, #menu{name=Name, type=?wxITEM_RADIO, _ = '_'}) of + [] -> ok; + [#menu{object=MenuItem}] -> %% Select the item in a radio group + wxMenuItem:check(MenuItem, [{check, true}]) + end. + update_menu(Menu, Item, Cmd) -> update_menu(Menu, Item, Cmd, undefined). @@ -1111,11 +1118,20 @@ menu_item(#menu{desc=Desc0, name=Name, help=Help, opts=Props, hk=HotKey}=ME, Par false -> Name end, - {Type,Check} = case proplists:get_value(crossmark, Props) of - undefined -> {?wxITEM_NORMAL, false}; - false -> {?wxITEM_CHECK, false}; - _ -> {?wxITEM_CHECK, true} %% grey or true - end, + {Type,Check} = + case proplists:is_defined(crossmark, Props) of + true -> + case proplists:get_value(crossmark, Props) of + false -> {?wxITEM_CHECK, false}; + _ -> {?wxITEM_CHECK, true} %% grey or true + end; + false -> + case proplists:get_value(radiomark, Props) of + undefined -> {?wxITEM_NORMAL, false}; + false -> {?wxITEM_RADIO, false}; + _ -> {?wxITEM_RADIO, true} + end + end, MI = wxMenuItem:new([{parentMenu, Parent}, {id,MenuId}, {text,Desc}, {kind, Type}, {help,Help}]), Cmd = case is_function(Command) of diff --git a/src/wings_shaders.erl b/src/wings_shaders.erl index b0ae4aae5..5089c3d74 100644 --- a/src/wings_shaders.erl +++ b/src/wings_shaders.erl @@ -4,7 +4,7 @@ %% Support for vertex & fragment shaders (for cards with OpenGL 2.0). %% %% Copyright (c) 2001-2011 Bjorn Gustavsson -%% +%% 2026 Micheus (matcap feature) %% See the file "license.terms" for information on usage and redistribution %% of this file, and for a DISCLAIMER OF ALL WARRANTIES. %% @@ -12,7 +12,7 @@ %% -module(wings_shaders). --export([init/0, compile_all/0, use_prog/2, +-export([init/0, shader_light/1, compile_all/0, use_prog/2, set_uloc/3, change_uloc/3, set_state/3, get_state/2, clear_state/2]). @@ -37,13 +37,27 @@ init() -> end, compile_all(). +shader_light(Id) when is_integer(Id) -> + case lists:keyfind(Id, 1, shader_lights()) of + {Id,Light} -> Light; + false -> camera_light + end; +shader_light(Light) -> + case lists:keyfind(Light, 2, shader_lights()) of + {Id,Light} -> Id; + false -> 2 %% hemi_light + end. + +shader_lights() -> [{1,camera_light},{2,hemi_light},{3,matcap_light}]. + compile_all() -> HL = [{'LightPosition', wings_pref:get_value(hl_lightpos)}, {'SkyColor', wings_pref:get_value(hl_skycol)}, {'GroundColor', wings_pref:get_value(hl_groundcol)}], Programs0 = [{1, camera_light, [], "One Camera Lights"}, - {2, hemilight, HL, "Hemispherical Lighting"}, + {2, hemi_light, HL, "Hemispherical Lighting"}, + {3, matcap_light, [], "MatCap Lighting"}, {background, background, [{blurry, 0.5}], ""}, {ambient_light, ambient_light, [], ""}, {infinite_light, infinite_light, [], ""}, @@ -92,6 +106,15 @@ use_prog(Name, RS) -> RS4 = set_uloc('ws_lightpos', LPos, RS3), RS5 = set_uloc('SkyColor', linear(hl_skycol), RS4), set_uloc('GroundColor', linear(hl_groundcol), RS5); + 3 -> + UseDiffuse = + case wings_pref:get_value(matcap_use_diffuse) of + true -> 1; + false -> 0 + end, + Rad = wings_pref:get_value(matcap_rotate) * math:pi() / 180.0, + RS4 = set_uloc('MatCapUseDiffuse', UseDiffuse, RS3), + set_uloc('MatCapRot', Rad, RS4); _ -> RS3 end; @@ -206,6 +229,7 @@ setup_uniforms(Prog, Vars, Name, Desc) -> wings_gl:set_uloc(Res, 'EnvBrdfMap', ?ENV_BRDF_MAP_UNIT), wings_gl:set_uloc(Res, 'EnvSpecMap', ?ENV_SPEC_MAP_UNIT), wings_gl:set_uloc(Res, 'EnvDiffMap', ?ENV_DIFF_MAP_UNIT), + wings_gl:set_uloc(Res, 'MatCapMap', ?MATCAP_MAP_UNIT), wings_gl:set_uloc(Res, 'AreaLTCMap', ?AREA_LTC_MAT_UNIT), [wings_gl:set_uloc(Res, Var, Val) || {Var,Val} <- Vars], diff --git a/src/wings_view.erl b/src/wings_view.erl index f738fbe7b..94d0e34c4 100644 --- a/src/wings_view.erl +++ b/src/wings_view.erl @@ -27,7 +27,6 @@ -import(lists, [foldl/3,flatmap/2,zip/2]). menu() -> - L = wings_pref:get_value(number_of_lights), [{?__(68,"Show"),{show, [{?__(1,"Ground Plane"),show_groundplane,?__(2,"Show the ground plane"), crossmark(show_groundplane)}, @@ -37,6 +36,12 @@ menu() -> ?__(49,"Show an informational text at the top of this Geometry window"), crossmark(show_info_text)}, separator, + {?__(19,"Show Edges"),show_edges,?__(20,"Show edges in workmode"),crossmark(show_edges)}, + {?__(72,"Show Backfaces"),show_backfaces, + ?__(73,"Show backfaces when there is a hole or hiddwn faces in an object"),crossmark(show_backfaces)}, + {?__(21,"Show Wireframe Backfaces"),show_wire_backfaces, + ?__(22,"Show wireframe backfaces"),crossmark(show_wire_backfaces)}, + separator, {?__(17,"Show Saved BB"),show_bb,?__(18,"Display any saved bounding box"),crossmark(show_bb)}, {?__(69,"Show BB Center"),show_bb_center, ?__(70,"Display the Center of any saved bounding box"),crossmark(show_bb_center)}, @@ -66,11 +71,6 @@ menu() -> {?__(9,"Shade"),shade,?__(10,"Display selected objects as shaded (same for all objects if nothing is selected)")}, {?__(11,"Toggle Wireframe"),toggle_wireframe, ?__(12,"Toggle display mode for selected objects (same for all objects if nothing is selected)")}, - {?__(19,"Show Edges"),show_edges,?__(20,"Show edges in workmode"),crossmark(show_edges)}, - {?__(72,"Show Backfaces"),show_backfaces, - ?__(73,"Show backfaces when there is a hole or hiddwn faces in an object"),crossmark(show_backfaces)}, - {?__(21,"Show Wireframe Backfaces"),show_wire_backfaces, - ?__(22,"Show wireframe backfaces"),crossmark(show_wire_backfaces)}, separator, {?__(5,"Workmode"),workmode,?__(6,"Toggle flat/smooth shading"), crossmark(workmode)}, @@ -79,12 +79,11 @@ menu() -> {?__(15,"Quick Smoothed Preview"),quick_preview, ?__(16,"Toggle the smooth proxy mode for all objects")}, separator | - [{?__(36,"Scene Lights"),scene_lights, - ?__(37,"Use the lights defined in the scene"), - crossmark(scene_lights)}, - {one_of(L == 1, ?__(38,"Use Camera Light"),?__(39,"Use a camera work Light")),toggle_lights, - one_of(L == 1, ?__(40,"Use two work lights"),?__(41,"Use a simple sky light simulation"))}, - separator, + [{?__(40,"Hemisphere Light"),{light,hemi_light},?__(41,"Use a simple sky light simulation"),[radiomark,false]}, + {?__(38,"Camera Light"),{light,camera_light},?__(39,"Use a camera work Light"),[radiomark,false]}, + {?__(80,"MatCap Light"),{light,matcap_light},?__(81,"Use a baked lighting texture"),[radiomark,false]}, + {?__(36,"Scene Lights"),{light,scene_lights},?__(37,"Use the lights defined in the scene"),[radiomark,false]}, + separator, {?__(31,"Orthographic View"),orthogonal_view, ?__(32,"Toggle between orthographic and perspective views"), crossmark(orthogonal_view)}, @@ -228,11 +227,8 @@ command(rotate_left, St) -> command(align_to_selection, St) -> aim(St), align_to_selection(St); -command(toggle_lights, St) -> - toggle_lights(), - St; -command(scene_lights, St) -> - toggle_option(scene_lights), +command({light,Light}, St) -> + select_light(Light), St; command(camera_settings, St) -> camera(St); @@ -698,8 +694,7 @@ auto_rotate_event_1(#keyboard{}=Kb, Tim) -> ?SET(auto_rotate, max(-45/60, Deg-Incr)), get_event(Tim); next -> keep; - {view, toggle_lights} -> toggle_lights(), keep; - {view, scene_lights} -> toggle_option(scene_lights), keep; + {view, {light,Light}} -> select_light(Light), keep; {view, reset} -> reset(), keep; {view, toggle_wireframe} -> toggle_option(workmode), keep; _Cmd -> @@ -798,8 +793,9 @@ init() -> wings_pref:set_default(filter_texture, true), wings_pref:set_default(frame_disregards_mirror, false), wings_pref:set_default(scene_lights, false), - Lights0 = wings_pref:get_value(number_of_lights), - update_menu(toggle_light(Lights0)). + LightId = wings_pref:get_value(number_of_lights), + Light = wings_shaders:shader_light(LightId), + update_light_menu(Light). initial_properties() -> [{workmode,true}, @@ -1141,29 +1137,36 @@ views_move(J, St, CurrentView, Views) -> wings_u:message(?__(1,"No such view [")++integer_to_list(J)++"]") end. -toggle_lights() -> - %% Invalidate displaylists so that shader data get set correctly - %% for materials - case wings_pref:get_value(scene_lights, true) of - false -> ok; - true -> toggle_option(scene_lights) - end, - Lights0 = wings_pref:get_value(number_of_lights), - update_menu(Lights0), - wings_wm:send(top_frame, {menu,{view, number_of_lights, toggle_light(Lights0)}}), - wings_pref:set_value(number_of_lights, toggle_light(Lights0)). - -toggle_light(Lights0) -> - 1 + (2 + Lights0) rem 2. - -update_menu(Lights0) -> - wings_menu:update_menu(view, toggle_lights, - one_of(Lights0 == 1, - ?__(2,"Use Camera Light"), - ?__(1,"Use Hemisphere Light")), - one_of(Lights0 == 1, - ?__(4,"Use a camera work light"), - ?__(3,"Use a simple sky light simulation"))). +select_light(scene_lights) -> + SceneLights = wings_pref:get_value(scene_lights, false), + EnabledLight = wings_light:any_enabled_lights(), + if EnabledLight and not SceneLights -> + wings_pref:set_value(scene_lights, true), + update_light_menu(scene_lights); + EnabledLight and SceneLights -> + ok; + true -> + OldId = wings_pref:get_value(number_of_lights), + OldLight = wings_shaders:shader_light(OldId), + wings_pref:set_value(scene_lights, false), + update_light_menu(OldLight) + end; +select_light(Light) -> + SceneLights = wings_pref:get_value(scene_lights, false), + OldId = wings_pref:get_value(number_of_lights), + NewId = wings_shaders:shader_light(Light), + if SceneLights -> + wings_pref:set_value(scene_lights, false), + wings_pref:set_value(number_of_lights, NewId), + update_light_menu(Light); + OldId =/= NewId -> + wings_pref:set_value(number_of_lights, NewId), + update_light_menu(Light); + true -> ok + end. + +update_light_menu(Light) -> + wings_menu:select_item({view,{light,Light}}). along(x) -> along(x, -90.0, 0.0); along(y) -> along(y, 0.0, 90.0); @@ -1278,9 +1281,6 @@ align_view_to_normal({Nx,Ny,Nz}) -> to_degrees(A) when is_float(A) -> A*180.0/math:pi(). -one_of(true, S, _) -> S; -one_of(false,_, S) -> S. - %%% %%% Export and import of views. %%% diff --git a/src/wings_view_win.erl b/src/wings_view_win.erl index 6827f0288..0a1fe1014 100644 --- a/src/wings_view_win.erl +++ b/src/wings_view_win.erl @@ -4,7 +4,7 @@ %% View window. %% %% Copyright (c) 2016 Dan Gudmundsson -%% +%% 2026 Micheus (matcap feature) %% See the file "license.terms" for information on usage and redistribution %% of this file, and for a DISCLAIMER OF ALL WARRANTIES. %% @@ -26,6 +26,7 @@ -define(HEMI_LIGHT, 1000). -define(HEMI_SKY, 1001). -define(HEMI_GROUND, 1002). +-define(MATCAP_LIGHT, 1003). -define(CAM_LIGHT, 1010). -define(CAM_POSX, 1013). -define(CAM_POSY, 1014). @@ -36,6 +37,9 @@ -define(CAM_BG_IMAGE, 1023). -define(CAM_BG_ROTATE, 1024). -define(SCENE_LIGHT, 1030). +-define(MATCAP_TEXTURE, 1040). +-define(MATCAP_ROTATE, 1041). +-define(MATCAP_USE_DIFFUSE, 1042). -define(AlignSz, 80). -define(SPACER_SIZE, 8). @@ -88,7 +92,10 @@ get_init_state(#st{} = St) -> cam_bg_rotate => wings_pref:get_value(show_bg_rotate), cam_bg_image => wings_pref:get_value(bg_image), hemi_sky => wings_pref:get_value(hl_skycol), - hemi_ground => wings_pref:get_value(hl_groundcol) + hemi_ground => wings_pref:get_value(hl_groundcol), + matcap_texture => wings_pref:get_value(matcap_texture), + matcap_rotate => wings_pref:get_value(matcap_rotate), + matcap_use_diffuse => wings_pref:get_value(matcap_use_diffuse) }. have_scene_light(St) -> @@ -100,10 +107,9 @@ have_scene_light(St) -> end. use_light(HaveSceneLight, SceneLight) -> - CameraLight = wings_pref:get_value(number_of_lights) == 1, - if SceneLight andalso HaveSceneLight -> scene_light; - CameraLight -> camera_light; - true -> hemi_light + LightId = wings_pref:get_value(number_of_lights), + if SceneLight andalso HaveSceneLight -> scene_lights; + true -> wings_shaders:shader_light(LightId) end. changed_state(Key0, Val0, Window, State) -> @@ -119,43 +125,38 @@ changed_state(Key0, Val0, Window, State) -> changed_state(number_of_lights, Val, #{light := Light0}) -> Light = case Val of 1 -> camera_light; - 2 -> hemi_light + 2 -> hemi_light; + 3 -> matcap_light end, {Light =/= Light0, {light, Light}}; changed_state(scene_lights, Bool, #{light:=Light0, have_scene_light:=HaveSceneLight}) -> Light = use_light(Bool, HaveSceneLight), {Light =/= Light0, {light, Light}}; changed_state(have_scene_light, Bool, #{have_scene_light:=HaveSceneLight}) -> - {Bool =/= HaveSceneLight, {have_scene_light, Bool}}; -changed_state(_Key, _Val, _State) -> - %% ?dbg("Ignore: ~p ~p in ~p~n",[_Key, _Val, _State]), - {false, ignored}. + {Bool =/= HaveSceneLight, {have_scene_light, Bool}}. change_state(Window, State) -> fun(Ev) -> forward_event(Ev, Window, State) end. %% Forward to view_window -forward_event({current_state, St}, Window, State0) -> +forward_event({current_state, St}, Window, #{have_scene_light:=HaveSceneLight0}=State0) -> HaveSceneLight = have_scene_light(St), - changed_state(have_scene_light, HaveSceneLight, Window, State0); -forward_event({view,Key,Val}, Window, State0) -> - changed_state(Key, Val, Window, State0); + SceneLights = wings_pref:get_value(scene_lights, false), + if HaveSceneLight=/=HaveSceneLight0 -> + changed_state(have_scene_light, HaveSceneLight, Window, State0); + SceneLights andalso HaveSceneLight -> + changed_state(scene_lights, SceneLights, Window, State0); + true -> + LightId = wings_pref:get_value(number_of_lights), + changed_state(number_of_lights, LightId, Window, State0) + end; %% Forward to wings forward_event({apply, {Light, radio}, _}, _Window, #{light := Prev}) -> - case {Light, Prev} of - {_, scene_light} -> - CameraLight = wings_pref:get_value(number_of_lights) == 1, - if Light =:= camera_light, CameraLight -> - wings_wm:send(geom, {action, {view, scene_lights}}); - Light =:= hemi_light, not CameraLight -> - wings_wm:send(geom, {action, {view, scene_lights}}); - true -> - wings_wm:send(geom, {action, {view, toggle_lights}}) - end; - {scene_light, _} -> - wings_wm:psend(geom, {action, {view, scene_lights}}); - {_, _} -> - wings_wm:psend(geom, {action, {view, toggle_lights}}) + AnyEnabledLight = wings_light:any_enabled_lights(), + case Light of + Prev -> ignore; + scene_lights when not AnyEnabledLight -> ignore; + _ -> wings_wm:psend(geom, {action, {view, {light,Light}}}) end, keep; forward_event({apply, {hemi_light, sky}, RGB}, Window, State) -> @@ -215,6 +216,29 @@ forward_event({apply, {camera_opts, bg_image}, Image}, Window, State) -> wings_wm:dirty(), change_state(Window, State#{cam_bg_image := Image}) end; +forward_event({apply, {matcap_light, matcap_texture}, Image}, Window, State) -> + case wings_light:load_matcap_texture(Image) of + {file_error, Err} -> + handle_error(file, Err, Image), + keep; + ok -> + SliderRef = wxWindow:findWindowById(?MATCAP_ROTATE), + Slider = wx:typeCast(SliderRef, wxSlider), + wings_pref:set_value(matcap_texture, Image), + wings_pref:set_value(matcap_rotate, 0.0), + wxSlider:setValue(Slider, round(0.0)), + wings_wm:dirty(), + change_state(Window, State#{matcap_texture := Image, matcap_rotate := 0.0}) + end; +forward_event({apply, {matcap_light, matcap_rot_slider}, Val}, Window, State) -> + wings_pref:set_value(matcap_rotate, Val), + wings_status:message(?MODULE, io_lib:format(?__(24,"MatCap Rotate: ~.3f"), [Val/1.0])), + wings_wm:dirty(), + change_state(Window, State#{matcap_rotate := Val}); +forward_event({apply, {matcap_light, matcap_use_diffuse}, Val}, Window, State) -> + wings_pref:set_value(matcap_use_diffuse, Val), + wings_wm:dirty(), + change_state(Window, State#{matcap_use_diffuse := Val}); forward_event(redraw, _, _) -> keep; @@ -245,6 +269,7 @@ init([Frame, _Ps, Os]) -> LightSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, ?__(1, "Light Settings")}]), HemL = create_hemilight(Panel, LightSz, SubFlags), CamL = create_cameralight(Panel, LightSz, SubFlags), + MatCapL = create_matcap(Panel, LightSz, SubFlags), SceneL = create_scenelight(Panel, LightSz, SubFlags), wxSizer:add(Szr, LightSz, [{border, 5}, {flag, ?wxEXPAND bor ?wxALL}]), @@ -253,7 +278,8 @@ init([Frame, _Ps, Os]) -> wxSizer:add(Szr, CameraSz, [{border, 5}, {flag, ?wxEXPAND bor ?wxALL}]), wxPanel:setSizer(Panel, Szr), - State0 = #{camera_light => CamL, hemi_light => HemL, scene_light => SceneL, camera_opts => CamS}, + State0 = #{camera_light => CamL, hemi_light => HemL, scene_lights => SceneL, + matcap_light => MatCapL, camera_opts => CamS}, State = ids_to_path(State0), wxWindow:connect(Panel, command_radiobutton_selected), wxWindow:connect(Panel, command_slider_updated), @@ -319,6 +345,34 @@ create_cameralight(Panel, LightSz, SubFlags) -> x_slider => PosCtrlX, y_slider => PosCtrlY, col => ColCtrl, ids => [{radio, ?CAM_LIGHT}, {pos_x, ?CAM_POSX}, {pos_y, ?CAM_POSY}, {col, ?CAM_COL}]}. +create_matcap(Panel, LightSz, SubFlags) -> + MatCapLB = wxRadioButton:new(Panel, ?MATCAP_LIGHT, ?__(1, "MatCap"), []), + Desc = ?__(2, "Baked lighting texture, ignores scene lights and projects a pre-rendered sphere onto the model."), + wxWindow:setToolTip(MatCapLB, wxToolTip:new(Desc)), + MatCapSz = wxBoxSizer:new(?wxVERTICAL), + + ImageCtrl = wxFilePickerCtrl:new(Panel, ?MATCAP_TEXTURE, []), + ImageSz = pre_text(?__(3, "Image:"), ImageCtrl, Panel), + wxSizer:add(MatCapSz, ImageSz, [{flag, ?wxEXPAND}]), + + MatcapRotate = wxSlider:new(Panel, ?MATCAP_ROTATE, 0, -180, 180, [{style, ?wxSL_HORIZONTAL}]), + wxWindow:setToolTip(MatcapRotate, wxToolTip:new(?__(5, "Set MatCap texture Rotation"))), + RotateSz = pre_text(?__(6, "Rotation:"), MatcapRotate, Panel), + wxSizer:add(MatCapSz, RotateSz, [{flag, ?wxEXPAND}]), + + UseDiffuse = wxCheckBox:new(Panel, ?MATCAP_USE_DIFFUSE, ?__(4, "Blend the diffuse (albedo) texture map"), [{style,?wxALIGN_LEFT}]), + wxSizer:add(MatCapSz, UseDiffuse, [{flag, ?wxEXPAND}]), + + wxSizer:add(LightSz, MatCapLB), + wxSizer:add(LightSz, MatCapSz, SubFlags), + wxSizer:addSpacer(LightSz, ?SPACER_SIZE), + wxCheckBox:connect(UseDiffuse, command_checkbox_clicked), + wxFilePickerCtrl:connect(ImageCtrl, command_filepicker_changed), + #{radio => MatCapLB, sz => MatCapSz, matcap_texture => ImageCtrl, + matcap_use_diffuse => UseDiffuse, matcap_rot_slider => MatcapRotate, + ids => [{radio, ?MATCAP_LIGHT}, {matcap_texture, ?MATCAP_TEXTURE}, + {matcap_use_diffuse, ?MATCAP_USE_DIFFUSE}, {matcap_rot_slider, ?MATCAP_ROTATE}]}. + create_scenelight(Panel, LightSz, SubFlags) -> SceneLB = wxRadioButton:new(Panel, ?SCENE_LIGHT, ?__(10, "Scene Light"), []), Desc = ?__(3, "Scene light, uses the scene lights, emulates a physically based renderer, uses all material properties"), @@ -373,14 +427,17 @@ pre_text(String, Ctrl, Parent) -> setup_gui(light, camera_light, #{camera_light:=Cam}) -> #{radio:=Button} = Cam, wxRadioButton:setValue(Button, true); -setup_gui(light, scene_light, #{scene_light:=Cam}) -> +setup_gui(light, scene_lights, #{scene_lights:=Cam}) -> + #{radio:=Button} = Cam, + wxRadioButton:setValue(Button, true); +setup_gui(light, matcap_light, #{matcap_light:=Cam}) -> #{radio:=Button} = Cam, wxRadioButton:setValue(Button, true); setup_gui(light, hemi_light, #{hemi_light:=Cam}) -> #{radio:=Button} = Cam, wxRadioButton:setValue(Button, true); -setup_gui(have_scene_light, Bool, #{scene_light:=Cam}) -> +setup_gui(have_scene_light, Bool, #{scene_lights:=Cam}) -> %% Scene light is available #{radio:=Button} = Cam, wxRadioButton:enable(Button, [{enable, Bool}]); @@ -418,6 +475,16 @@ setup_gui(hemi_sky, RGB, #{hemi_light:=Hemi}) -> setup_gui(hemi_ground, RGB, #{hemi_light:=Hemi}) -> #{ground:=Ctrl} = Hemi, ww_color_ctrl:setColor(Ctrl, RGB); + +setup_gui(matcap_texture, FileName, #{matcap_light:=Cam}) -> + #{matcap_texture:=Slider} = Cam, + wxFilePickerCtrl:setPath(Slider, FileName); +setup_gui(matcap_rotate, Val, #{matcap_light:=Cam}) -> + #{matcap_rot_slider:=Slider} = Cam, + wxSlider:setValue(Slider, round(Val)); +setup_gui(matcap_use_diffuse, Bool, #{matcap_light:=Cam}) -> + #{matcap_use_diffuse:=Ctrl} = Cam, + wxCheckBox:setValue(Ctrl, Bool); setup_gui(_Key, _Val, _) -> ?dbg("Missing impl: ~p ~p~n",[_Key,_Val]), ok. @@ -432,6 +499,10 @@ handle_event(#wx{id=?CAM_BG,event=#wxCommand{type=command_checkbox_clicked, comm #{bg_slider:=Slider} = Cam, wxSlider:enable(Slider, [{enable, Val == 1}]), {noreply, State}; +handle_event(#wx{id=?MATCAP_USE_DIFFUSE,event=#wxCommand{type=command_checkbox_clicked}=Ev}, #{ids:=Ids} = State) -> + What = maps:get(?MATCAP_USE_DIFFUSE, Ids), + forward_setting(What, Ev), + {noreply, State}; handle_event(#wx{id=Id, event=#wxMouse{type=enter_window}}=Ev, #{ids:=Ids} = State) -> Msg = case maps:get(Id, Ids, none) of {hemi_light, _} -> ?__(2, "Change light color"); @@ -442,6 +513,9 @@ handle_event(#wx{id=Id, event=#wxMouse{type=enter_window}}=Ev, #{ids:=Ids} = Sta {camera_opts, bg_slider} -> ?__(12, "Blur environment"); {camera_opts, bg_rot_slider} -> ?__(14, "Rotate environment"); {camera_opts, bg_image} -> ?__(13, "Change environment image"); + {matcap_light, matcap_texture} -> ?__(15, "Change matcap texture"); + {matcap_light, matcap_rot_slider} -> ?__(16, "Rotate matcap texture"); + {matcap_light, matcap_use_diffuse} -> ?__(17, "Blend diffuse colour/map and matcap texture"); _What -> ?__(1, "Edit camera and light settings") end, wings_status:message(?MODULE, Msg), diff --git a/textures/matcap/0A0A0A_A9A9A9_525252_747474-128px.png b/textures/matcap/0A0A0A_A9A9A9_525252_747474-128px.png new file mode 100644 index 000000000..11aa77b78 Binary files /dev/null and b/textures/matcap/0A0A0A_A9A9A9_525252_747474-128px.png differ diff --git a/textures/matcap/1A2461_3D70DB_2C3C8F_2C6CAC-128px.png b/textures/matcap/1A2461_3D70DB_2C3C8F_2C6CAC-128px.png new file mode 100644 index 000000000..01c67f000 Binary files /dev/null and b/textures/matcap/1A2461_3D70DB_2C3C8F_2C6CAC-128px.png differ diff --git a/textures/matcap/1B1B1B_999999_575757_747474-128px.png b/textures/matcap/1B1B1B_999999_575757_747474-128px.png new file mode 100644 index 000000000..4b70775e6 Binary files /dev/null and b/textures/matcap/1B1B1B_999999_575757_747474-128px.png differ diff --git a/textures/matcap/1D3FCC_051B5F_81A0F2_5579E9-128px.png b/textures/matcap/1D3FCC_051B5F_81A0F2_5579E9-128px.png new file mode 100644 index 000000000..8694a6ae9 Binary files /dev/null and b/textures/matcap/1D3FCC_051B5F_81A0F2_5579E9-128px.png differ diff --git a/textures/matcap/27222B_677491_484F6A_5D657A-128px.png b/textures/matcap/27222B_677491_484F6A_5D657A-128px.png new file mode 100644 index 000000000..b7994d442 Binary files /dev/null and b/textures/matcap/27222B_677491_484F6A_5D657A-128px.png differ diff --git a/textures/matcap/293D21_ABC692_73B255_667C5C-128px.png b/textures/matcap/293D21_ABC692_73B255_667C5C-128px.png new file mode 100644 index 000000000..f35147205 Binary files /dev/null and b/textures/matcap/293D21_ABC692_73B255_667C5C-128px.png differ diff --git a/textures/matcap/34352A_718184_50605E_6E6761-128px.png b/textures/matcap/34352A_718184_50605E_6E6761-128px.png new file mode 100644 index 000000000..bbfab51cc Binary files /dev/null and b/textures/matcap/34352A_718184_50605E_6E6761-128px.png differ diff --git a/textures/matcap/392307_B3AE7D_6D5618_847C42-128px.png b/textures/matcap/392307_B3AE7D_6D5618_847C42-128px.png new file mode 100644 index 000000000..17df1bee6 Binary files /dev/null and b/textures/matcap/392307_B3AE7D_6D5618_847C42-128px.png differ diff --git a/textures/matcap/3A2412_A78B5F_705434_836C47-128px.png b/textures/matcap/3A2412_A78B5F_705434_836C47-128px.png new file mode 100644 index 000000000..f66ddc353 Binary files /dev/null and b/textures/matcap/3A2412_A78B5F_705434_836C47-128px.png differ diff --git a/textures/matcap/3F4441_D1D7D6_888F87_A2ADA1-128px.png b/textures/matcap/3F4441_D1D7D6_888F87_A2ADA1-128px.png new file mode 100644 index 000000000..acac6f001 Binary files /dev/null and b/textures/matcap/3F4441_D1D7D6_888F87_A2ADA1-128px.png differ diff --git a/textures/matcap/4B4A3A_94A3A4_68766F_988475-128px.png b/textures/matcap/4B4A3A_94A3A4_68766F_988475-128px.png new file mode 100644 index 000000000..c78f70382 Binary files /dev/null and b/textures/matcap/4B4A3A_94A3A4_68766F_988475-128px.png differ diff --git a/textures/matcap/4F4F4F_9C9C9C_121212_7C7C7C-128px.png b/textures/matcap/4F4F4F_9C9C9C_121212_7C7C7C-128px.png new file mode 100644 index 000000000..6fc838d49 Binary files /dev/null and b/textures/matcap/4F4F4F_9C9C9C_121212_7C7C7C-128px.png differ diff --git a/textures/matcap/525050_D4D3D3_959393_ACACAC-128px.png b/textures/matcap/525050_D4D3D3_959393_ACACAC-128px.png new file mode 100644 index 000000000..f1cb0f747 Binary files /dev/null and b/textures/matcap/525050_D4D3D3_959393_ACACAC-128px.png differ diff --git a/textures/matcap/555555_C8C8C8_8B8B8B_A4A4A4-128px.png b/textures/matcap/555555_C8C8C8_8B8B8B_A4A4A4-128px.png new file mode 100644 index 000000000..c9b085537 Binary files /dev/null and b/textures/matcap/555555_C8C8C8_8B8B8B_A4A4A4-128px.png differ diff --git a/textures/matcap/586A51_CCD5AA_8C9675_8DBBB7-128px.png b/textures/matcap/586A51_CCD5AA_8C9675_8DBBB7-128px.png new file mode 100644 index 000000000..79b29d14f Binary files /dev/null and b/textures/matcap/586A51_CCD5AA_8C9675_8DBBB7-128px.png differ diff --git a/textures/matcap/5F5F5F_BDBDBD_A4A4A4_9C9C9C-128px.png b/textures/matcap/5F5F5F_BDBDBD_A4A4A4_9C9C9C-128px.png new file mode 100644 index 000000000..084bafb11 Binary files /dev/null and b/textures/matcap/5F5F5F_BDBDBD_A4A4A4_9C9C9C-128px.png differ diff --git a/textures/matcap/647171_1F3349_2A475C_87A5AD-128px.png b/textures/matcap/647171_1F3349_2A475C_87A5AD-128px.png new file mode 100644 index 000000000..2da8592e8 Binary files /dev/null and b/textures/matcap/647171_1F3349_2A475C_87A5AD-128px.png differ diff --git a/textures/matcap/68493E_B2AAA9_978C8C_130907-128px.png b/textures/matcap/68493E_B2AAA9_978C8C_130907-128px.png new file mode 100644 index 000000000..5dbc6010e Binary files /dev/null and b/textures/matcap/68493E_B2AAA9_978C8C_130907-128px.png differ diff --git a/textures/matcap/706962_24211E_BCB6AF_ACA494-128px.png b/textures/matcap/706962_24211E_BCB6AF_ACA494-128px.png new file mode 100644 index 000000000..ac0c70dd2 Binary files /dev/null and b/textures/matcap/706962_24211E_BCB6AF_ACA494-128px.png differ diff --git a/textures/matcap/713A28_A87661_3A160D_9B6454-128px.png b/textures/matcap/713A28_A87661_3A160D_9B6454-128px.png new file mode 100644 index 000000000..fc1b802f5 Binary files /dev/null and b/textures/matcap/713A28_A87661_3A160D_9B6454-128px.png differ diff --git a/textures/matcap/71623B_ECDE8C_30250A_ABA69A-128px.png b/textures/matcap/71623B_ECDE8C_30250A_ABA69A-128px.png new file mode 100644 index 000000000..976661ddf Binary files /dev/null and b/textures/matcap/71623B_ECDE8C_30250A_ABA69A-128px.png differ diff --git a/textures/matcap/736655_D9D8D5_2F281F_B1AEAB-128px.png b/textures/matcap/736655_D9D8D5_2F281F_B1AEAB-128px.png new file mode 100644 index 000000000..686e3243f Binary files /dev/null and b/textures/matcap/736655_D9D8D5_2F281F_B1AEAB-128px.png differ diff --git a/textures/matcap/763B28_D0BDB8_ADA39E_1E1D1D-128px.png b/textures/matcap/763B28_D0BDB8_ADA39E_1E1D1D-128px.png new file mode 100644 index 000000000..8163f5382 Binary files /dev/null and b/textures/matcap/763B28_D0BDB8_ADA39E_1E1D1D-128px.png differ diff --git a/textures/matcap/7877EE_D87FC5_75D9C7_1C78C0-128px.png b/textures/matcap/7877EE_D87FC5_75D9C7_1C78C0-128px.png new file mode 100644 index 000000000..938d5c2fa Binary files /dev/null and b/textures/matcap/7877EE_D87FC5_75D9C7_1C78C0-128px.png differ diff --git a/textures/matcap/7F5134_22120A_452110_9F7D5F-128px.png b/textures/matcap/7F5134_22120A_452110_9F7D5F-128px.png new file mode 100644 index 000000000..0a8e3cb96 Binary files /dev/null and b/textures/matcap/7F5134_22120A_452110_9F7D5F-128px.png differ diff --git a/textures/matcap/8B892C_D4E856_475E2D_47360A-128px.png b/textures/matcap/8B892C_D4E856_475E2D_47360A-128px.png new file mode 100644 index 000000000..791651632 Binary files /dev/null and b/textures/matcap/8B892C_D4E856_475E2D_47360A-128px.png differ diff --git a/textures/matcap/A0A8B0_424336_E7E9EF_545C5C-128px.png b/textures/matcap/A0A8B0_424336_E7E9EF_545C5C-128px.png new file mode 100644 index 000000000..95f19bad6 Binary files /dev/null and b/textures/matcap/A0A8B0_424336_E7E9EF_545C5C-128px.png differ diff --git a/textures/matcap/AB2C2C_EBB4B3_561212_DE8484-128px.png b/textures/matcap/AB2C2C_EBB4B3_561212_DE8484-128px.png new file mode 100644 index 000000000..8268076ba Binary files /dev/null and b/textures/matcap/AB2C2C_EBB4B3_561212_DE8484-128px.png differ diff --git a/textures/matcap/AbstractMatcap_AquaLine.jpg b/textures/matcap/AbstractMatcap_AquaLine.jpg new file mode 100644 index 000000000..d50410b5f Binary files /dev/null and b/textures/matcap/AbstractMatcap_AquaLine.jpg differ diff --git a/textures/matcap/AbstractMatcap_GreyMatter.jpg b/textures/matcap/AbstractMatcap_GreyMatter.jpg new file mode 100644 index 000000000..76ec5ed78 Binary files /dev/null and b/textures/matcap/AbstractMatcap_GreyMatter.jpg differ diff --git a/textures/matcap/BlueToon.png b/textures/matcap/BlueToon.png new file mode 100644 index 000000000..45cf6c7f5 Binary files /dev/null and b/textures/matcap/BlueToon.png differ diff --git a/textures/matcap/ClayTritone_MatCap.png b/textures/matcap/ClayTritone_MatCap.png new file mode 100644 index 000000000..386ff29df Binary files /dev/null and b/textures/matcap/ClayTritone_MatCap.png differ diff --git a/textures/matcap/GreyTritone_MatCap.png b/textures/matcap/GreyTritone_MatCap.png new file mode 100644 index 000000000..4857b4bc4 Binary files /dev/null and b/textures/matcap/GreyTritone_MatCap.png differ diff --git a/textures/matcap/LitSphere1.png b/textures/matcap/LitSphere1.png new file mode 100644 index 000000000..91ca05e22 Binary files /dev/null and b/textures/matcap/LitSphere1.png differ diff --git a/textures/matcap/README.md b/textures/matcap/README.md new file mode 100644 index 000000000..b4bf8690a --- /dev/null +++ b/textures/matcap/README.md @@ -0,0 +1,53 @@ +
All matcap resources were sourced from publicly available internet repositories, shared without restrictions or free of charge.
+We are distributing the matcaps in 128×128 resolution, which is sufficient for most uses, though the original sources provide higher‑resolution versions. They cover materials such as glass, glossy paint, metal, clay, and others.
+ +by [Petrosfera](https://petrosfera.gumroad.com/l/abstractmatcapsvol1?a=784689267)