1%% 2%% wings_render.erl -- 3%% 4%% Render all objects and helpers (such as axes) in the scene. 5%% Used for the Geometry and AutoUV windows. 6%% 7%% Copyright (c) 2001-2011 Bjorn Gustavsson 8%% 9%% See the file "license.terms" for information on usage and redistribution 10%% of this file, and for a DISCLAIMER OF ALL WARRANTIES. 11%% 12%% $Id$ 13%% 14 15-module(wings_render). 16-export([init/0, 17 render/1, 18 %% polygonOffset/1, enable_lighting/1,disable_lighting/0, 19 draw_orig_sel_dl/1 20 ]). 21 22-define(NEED_OPENGL, 1). 23-include("wings.hrl"). 24 25-import(lists, [foldl/3]). 26 27init() -> 28 wings_pref:set_default(multisample, true), 29 wings_pref:set_default(smooth_alpha, 0.850013), 30 init_polygon_stipple(). 31 32%% render(St) 33%% Render the entire contents of a Geometry or AutoUV window, 34%% including groundplane and axes. Use the contents of the display 35%% lists maintained by wings_dl. All display lists must 36%% already exist; no display lists are created by this function. 37 38render(#st{selmode=Mode}=St) -> 39 ?CHECK_ERROR(), 40 gl:pushAttrib(?GL_CURRENT_BIT bor ?GL_ENABLE_BIT bor 41 ?GL_TEXTURE_BIT bor ?GL_POLYGON_BIT bor 42 ?GL_LINE_BIT bor ?GL_COLOR_BUFFER_BIT), 43 gl:enable(?GL_DEPTH_TEST), 44 gl:enable(?GL_CULL_FACE), 45 case wings_pref:get_value(multisample) of 46 true -> gl:enable(?GL_MULTISAMPLE); 47 _ -> gl:disable(?GL_MULTISAMPLE) 48 end, 49 {PM,MM,SceneLights} = wings_view:load_matrices(true), 50 View = wings_view:current(), 51 mini_axis_icon(View, MM), 52 show_saved_bb(St), 53 show_bb_center(St), 54 user_clipping_planes(on), 55 RS = render_objects(Mode, PM, MM, SceneLights), 56 user_clipping_planes(off), 57 draw_background(MM), 58 ground_and_axes(View, PM,MM, RS), 59 show_camera_image_plane(), 60 gl:popAttrib(), 61 call_post_hook(St), 62 wings_develop:gl_error_check("Rendering scene"). 63 64%% draw_orig_sel_dl(Mode) -> ok. 65%% Set up a display list to draw the original selection. To 66%% be called from wings_vec when there is a secondary selection. 67 68-spec draw_orig_sel_dl(wings_sel:mode()) -> 'ok'. 69draw_orig_sel_dl(Mode) -> 70 wings_dl:map(fun(#dlo{orig_sel=none,sel=Dlist0}=D, _) -> 71 Draw = draw_orig_sel_fun(Mode, Dlist0), 72 Dlist = {call,Draw,Dlist0}, 73 D#dlo{orig_sel=Dlist} 74 end, []). 75 76call_post_hook(St) -> 77 case wings_wm:lookup_prop(postdraw_hook) of 78 none -> ok; 79 {value,{_Id,Fun}} -> Fun(St) 80 end. 81 82polygonOffset(M) -> 83 case get(polygon_offset) of 84 undefined -> 85 F = wings_pref:get_value(polygon_offset_f,1.0), 86 R = wings_pref:get_value(polygon_offset_r,1.0), 87 put(polygon_offset, {F,R}), 88 gl:polygonOffset(M*F, M*R); 89 {F,R} -> 90 gl:polygonOffset(M*F, M*R) 91 end. 92 93%% According Game Programming Gems chap 4.1 (By Eric Lengyel) 94%% http://www.terathon.com/books/code/Listing9.1.txt 95%% http://terathon.com/gdc07_lengyel.pdf 96%% Minimum Eps for 24b depth buffer (skip calc and use min value) 97non_polygon_offset(Offset, TPM) -> 98 ProjMat = e3d_transform:matrix(TPM), 99 Eps = 1.0 - Offset*5.0e-7, 100 E33 = element(11, ProjMat), %% Modify entry {3,3} 101 gl:loadMatrixd(setelement(11, ProjMat, E33*Eps)). 102 103%%% 104%%% Internal functions follow. 105%%% 106 107init_polygon_stipple() -> 108 P = <<16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 109 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 110 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 111 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 112 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 113 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 114 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 115 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 116 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 117 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 118 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 119 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 120 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 121 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 122 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77, 123 16#DD,16#DD,16#DD,16#DD,16#77,16#77,16#77,16#77>>, 124 gl:polygonStipple(P). 125 126setup_scene_lights(false, _, RS) -> 127 {false, RS}; 128setup_scene_lights(true, Lights, RS0) -> 129 {Amb0, SL} = wings_light:global_lights(Lights), 130 case Amb0 of 131 [] -> 132 %% Must render all objects black first otherwise we blend with bg 133 RS1 = wings_shaders:use_prog(ambient_light, RS0), 134 RS = wings_shaders:set_uloc(light_diffuse, {0.0,0.0,0.0,1.0}, RS1), 135 {SL, RS}; 136 [Amb|RestAmb] -> 137 RS = wings_light:setup_light(Amb, RS0), 138 {RestAmb ++ SL, RS} 139 end. 140 141render_objects(Mode, PM, MM, UseSceneLights) -> 142 Dls = wings_dl:display_lists(), 143 {Open,Closed,Lights} = split_objects(Dls, [], [], []), 144 NonLights = Open ++ Closed, 145 RS0 = #{ws_eyepoint => e3d_mat:mul_point(e3d_transform:inv_matrix(MM), {0.0,0.0,0.0}), 146 view_from_world => MM}, 147 RS1 = render_lights(Lights, Mode, PM, RS0), 148 {SL, RS2} = setup_scene_lights(UseSceneLights, Lights, RS1), 149 case wings_wm:get_prop(workmode) of 150 false -> 151 RS10 = case UseSceneLights of 152 true -> render_smooth_objects(Open, Closed, ambient, RS2); %% amb pass 153 false -> RS2 154 end, 155 RS21 = render_smooth_objects(Open, Closed, SL, RS10), 156 RS22 = render_wire(NonLights, Mode, true, RS21), 157 render_sel_highlight(NonLights, Mode, true, PM, RS22); 158 true -> 159 RS10 = case UseSceneLights of 160 true -> render_work_objects(Open, Closed, ambient, RS2); %% amb pass 161 false -> RS2 162 end, 163 RS21 = render_work_objects(Open, Closed, SL, RS10), 164 RS22 = render_wire(NonLights, Mode, false, RS21), 165 render_sel_highlight(NonLights, Mode, false, PM, RS22) 166 end. 167 168render_lights([], _Mode, _PM, RS0) -> 169 RS0; 170render_lights(Lights, Mode, PM, RS0) -> 171 RS1 = wings_shaders:use_prog(light_light, RS0), 172 gl:color4ub(255, 255, 255, 255), 173 gl:disable(?GL_CULL_FACE), 174 gl:enable(?GL_POLYGON_OFFSET_FILL), 175 polygonOffset(2.0), 176 RS2 = render_work_objects_0(Lights, false, RS1), 177 gl:color4ub(255, 255, 255, 255), 178 RS21 = wings_shaders:use_prog(0, RS2), 179 polygonOffset(0.0), 180 gl:disable(?GL_POLYGON_OFFSET_FILL), 181 AreaLights = [D || #dlo{src_we=We}=D <- Lights, ?IS_AREA_LIGHT(We)], 182 case AreaLights of 183 [] -> RS21; 184 AreaLights -> 185 RS22 = render_wire(AreaLights, Mode, true, RS21), 186 RS23 = render_sel_highlight(AreaLights, Mode, false, PM, RS22), 187 gl:color4ub(255, 255, 255, 255), %% Reset vertex col from sel_col or edge_col 188 RS23 189 end. 190 191render_work_objects(Open, Closed, SceneLights, RS0) -> 192 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_FILL), 193 gl:enable(?GL_POLYGON_OFFSET_FILL), 194 polygonOffset(2.0), 195 gl:shadeModel(?GL_SMOOTH), 196 RS1 = enable_lighting(SceneLights, RS0), 197 RS2 = render_work_objects_0(Closed, SceneLights, RS1), 198 wings_pref:get_value(show_backfaces) andalso gl:disable(?GL_CULL_FACE), 199 RS3 = render_work_objects_0(Open, SceneLights, RS2), 200 gl:enable(?GL_CULL_FACE), 201 RS = disable_lighting(RS3), 202 gl:shadeModel(?GL_FLAT), 203 RS. 204 205render_work_objects_0(Dls, [Light|SLs], RS0) -> 206 RS1 = wings_light:setup_light(Light, RS0), 207 RS = render_work_objects_1(Dls, true, RS1), 208 render_work_objects_0(Dls, SLs, RS); 209render_work_objects_0(_, [], RS0) -> 210 RS0; 211render_work_objects_0(Dls, _, RS0) -> 212 render_work_objects_1(Dls, false, RS0). 213 214 215render_work_objects_1([D|Dls], SceneLights, RS0) -> 216 RS = render_object(D, true, false, SceneLights, RS0), 217 render_work_objects_1(Dls, SceneLights, RS); 218render_work_objects_1([], _, RS) -> RS. 219 220render_smooth_objects(Open, Closed, SceneLights, RS0) -> 221 gl:shadeModel(?GL_SMOOTH), 222 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_FILL), 223 RS1 = enable_lighting(SceneLights, RS0), 224 gl:enable(?GL_POLYGON_OFFSET_FILL), 225 polygonOffset(2.0), 226 gl:enable(?GL_CULL_FACE), 227 RS2 = render_smooth_objects_0(Closed, false, SceneLights, RS1), 228 wings_pref:get_value(show_backfaces) andalso gl:disable(?GL_CULL_FACE), 229 RS3 = render_smooth_objects_0(Open, false, SceneLights, RS2), 230 case maps:get(transparent, RS3, false) of 231 true -> 232 %% Render a alpha test pass for almost opaque fragments 233 gl:enable(?GL_ALPHA_TEST), 234 gl:alphaFunc(?GL_GEQUAL, wings_pref:get_value(smooth_alpha)), 235 gl:enable(?GL_BLEND), 236 gl:blendFunc(?GL_SRC_ALPHA, ?GL_ONE_MINUS_SRC_ALPHA), 237 RS5 = render_smooth_objects_0(Open, true, false, RS3), 238 gl:enable(?GL_CULL_FACE), 239 RS6 = render_smooth_objects_0(Closed, true, false, RS5), 240 gl:disable(?GL_ALPHA_TEST), 241 gl:depthFunc(?GL_LESS), 242 243 gl:depthMask(?GL_FALSE), 244 RS9 = render_smooth_objects_0(Closed, true, SceneLights, RS6), 245 wings_pref:get_value(show_backfaces) andalso gl:disable(?GL_CULL_FACE), 246 RS10 = render_smooth_objects_0(Open, true, SceneLights, RS9), 247 RS = disable_lighting(RS10), 248 gl:enable(?GL_CULL_FACE), 249 gl:disable(?GL_BLEND), 250 gl:depthMask(?GL_TRUE), 251 RS; 252 false -> 253 RS = disable_lighting(RS3), 254 gl:enable(?GL_CULL_FACE), 255 RS 256 end. 257 258render_smooth_objects_0([], _, _, RS0) -> 259 RS0; 260render_smooth_objects_0(Dls, RenderTrans, [Light|SLs], RS0) -> 261 RS1 = wings_light:setup_light(Light, RS0), 262 RS = render_smooth_objects_1(Dls, RenderTrans, true, RS1), 263 render_smooth_objects_0(Dls, RenderTrans, SLs, RS); 264render_smooth_objects_0(_, _, [], RS0) -> 265 RS0; 266render_smooth_objects_0(Dls, RenderTrans, _, RS0) -> 267 render_smooth_objects_1(Dls, RenderTrans, false, RS0). 268 269render_smooth_objects_1([D|Dls], RenderTrans, SceneLights, RS0) -> 270 RS = render_object(D, false, RenderTrans, SceneLights, RS0), 271 render_smooth_objects_1(Dls, RenderTrans, SceneLights, RS); 272render_smooth_objects_1([], _, _, RS) -> RS. 273 274render_object(#dlo{drag={matrix,_,_,DragMat}}=D, Work, RT, SceneLights, RS0) -> 275 gl:pushMatrix(), 276 gl:multMatrixf(DragMat), 277 Prev = wings_shaders:get_state(ws_matrix, RS0), 278 RS1 = wings_shaders:set_uloc(ws_matrix, e3d_mat:compress(e3d_mat:mul(DragMat, Prev)), RS0), 279 RS2 = render_object_1(D, Work, RT, SceneLights, RS1), 280 RS = wings_shaders:set_uloc(ws_matrix, Prev, RS2), 281 gl:popMatrix(), 282 RS; 283render_object(D, Work, RT, SceneLights, RS) -> 284 render_object_1(D, Work, RT, SceneLights, RS). 285 286render_object_1(#dlo{mirror=none}=D, Work, RenderTrans, SceneLights, RS) -> 287 render_object_2(D, Work, RenderTrans, SceneLights, RS); 288render_object_1(#dlo{mirror=MirrorMat}=DL, Work, RenderTrans, SceneLights, RS0) -> 289 RS1 = render_object_2(DL, Work, RenderTrans, SceneLights, RS0), 290 gl:frontFace(?GL_CW), 291 gl:pushMatrix(), 292 gl:multMatrixf(MirrorMat), 293 Prev = wings_shaders:get_state(ws_matrix, RS0), 294 RS2 = wings_shaders:set_uloc(ws_matrix, e3d_mat:mul(MirrorMat, Prev), RS1), 295 RS3 = render_object_2(DL, Work, RenderTrans, SceneLights, RS2), 296 RS = wings_shaders:set_uloc(ws_matrix, Prev, RS3), 297 gl:popMatrix(), 298 gl:frontFace(?GL_CCW), 299 RS. 300 301render_object_2(D, true, _, SceneLights, RS) -> 302 render_plain(D, SceneLights, RS); 303render_object_2(D, false, RenderTrans, SceneLights, RS) -> 304 render_smooth(D, RenderTrans, SceneLights, RS). 305 306render_plain(#dlo{work=Faces,src_we=We,proxy=false}, _SceneLights, RS) -> 307 case wire(We) of 308 _ when ?IS_LIGHT(We) -> wings_dl:call(Faces, RS); 309 false -> wings_dl:call(Faces, RS); 310 true -> RS 311 end; 312render_plain(#dlo{proxy_data=PD, drag=Drag}, SceneLights, RS0) -> 313 polygonOffset(3.0), 314 Faces = wings_proxy:flat_dl(PD), 315 Key = case Drag =:= none of 316 true -> proxy_static_opacity; 317 false -> proxy_moving_opacity 318 end, 319 if SceneLights =:= false -> 320 Blend = wings_gl:is_ext('GL_ARB_imaging') andalso wings_pref:get_value(Key), 321 case Blend of 322 false -> 323 wings_dl:call(Faces, RS0); 324 1.0 -> 325 wings_dl:call(Faces, RS0); 326 _ -> 327 gl:enable(?GL_BLEND), 328 gl:blendFunc(?GL_CONSTANT_ALPHA, ?GL_ONE_MINUS_CONSTANT_ALPHA), 329 gl:blendColor(0.0, 0.0, 0.0, Blend), 330 RS = wings_dl:call(Faces, RS0), 331 gl:disable(?GL_BLEND), 332 RS 333 end; 334 true -> 335 wings_dl:call(Faces, RS0) 336 end. 337 338render_smooth(#dlo{work=Work,smooth=Smooth0, proxy=Proxy,proxy_data=PD, transparent=Trans0}, 339 RenderTrans, _SceneLights, RS) -> 340 {Smooth, Trans} = case Proxy of 341 false -> {Smooth0, Trans0}; 342 true -> wings_proxy:smooth_dl(PD) 343 end, 344 case {Smooth,RenderTrans} of 345 {none,false} -> 346 wings_dl:call(Work, RS); 347 {[Op,_],false} -> 348 RS1 = if Trans -> RS#{transparent=>Trans}; 349 true -> RS 350 end, 351 wings_dl:call(Op, RS1); 352 {[_,Tr],true} -> 353 wings_dl:call(Tr, RS); 354 {_,_} -> 355 RS 356 end. 357 358enable_lighting(false, #{}=RS0) -> 359 Lighting = wings_pref:get_value(number_of_lights), 360 gl:color4ub(255, 255, 255, 255), %% Needed when vertex colors are not set 361 wings_shaders:use_prog(Lighting, RS0); 362enable_lighting(ambient, RS) -> 363 RS; 364enable_lighting(_, RS) -> 365 gl:color4ub(255, 255, 255, 255), 366 gl:depthFunc(?GL_LEQUAL), 367 gl:enable(?GL_BLEND), 368 gl:blendFunc(?GL_ONE, ?GL_ONE), 369 RS. 370 371disable_lighting(RS0) -> 372 RS = wings_shaders:use_prog(0, RS0), 373 gl:depthFunc(?GL_LESS), 374 gl:disable(?GL_BLEND), 375 gl:depthMask(?GL_TRUE), 376 RS. 377 378render_wire(Dls, SelMode, false, RS0) -> 379 WOs = wings_wm:get_prop(wireframed_objects), 380 Show = wings_pref:get_value(show_edges), 381 case split_wires(Dls, WOs, Show, [], [], []) of 382 {[],[],[]} -> RS0; 383 {Ws,Os,PWs} -> 384 case {SelMode,wings_pref:get_value(edge_color)} of 385 {body,{0.0,0.0,0.0}} -> 386 gl:color3f(0.3, 0.3, 0.3); 387 {_,EdgeColor} -> 388 gl:color3fv(EdgeColor) 389 end, 390 case wings_pref:get_value(aa_edges) of 391 true -> 392 gl:enable(?GL_LINE_SMOOTH), 393 gl:enable(?GL_BLEND), 394 gl:blendFunc(?GL_SRC_ALPHA, ?GL_ONE_MINUS_SRC_ALPHA), 395 gl:hint(?GL_LINE_SMOOTH_HINT, ?GL_NICEST), 396 ok; 397 false -> 398 ok 399 end, 400 gl:lineWidth(edge_width(SelMode)), 401 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_LINE), 402 gl:depthFunc(?GL_LEQUAL), 403 wings_wm:get_prop(show_wire_backfaces) 404 andalso gl:disable(?GL_CULL_FACE), 405 Cage = fun(D,RS) -> render_wire_object(D, cage, RS) end, 406 RS1 = foldl(Cage, RS0, Ws), 407 gl:disable(?GL_CULL_FACE), 408 RS2 = foldl(Cage, RS1, Os), 409 gl:enable(?GL_CULL_FACE), 410 gl:color3fv(wings_pref:get_value(edge_color)), 411 gl:lineWidth(1.0), 412 RS3 = foldl(Cage, RS2, PWs), 413 gl:enable(?GL_CULL_FACE), 414 gl:depthFunc(?GL_LESS), 415 RS3 416 end; 417render_wire(Dls, _, true, RS0) -> 418 gl:enable(?GL_CULL_FACE), 419 gl:disable(?GL_POLYGON_OFFSET_FILL), 420 gl:depthMask(?GL_TRUE), 421 gl:shadeModel(?GL_FLAT), 422 gl:depthFunc(?GL_LEQUAL), 423 WOs = wings_wm:get_prop(wireframed_objects), 424 {Ws,[],PWs} = split_wires(Dls, WOs, false, [], [], []), 425 gl:color3fv(wings_pref:get_value(edge_color)), 426 gl:lineWidth(1.0), 427 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_LINE), 428 RS1 = foldl(fun(D,RS) -> render_wire_object(D, cage, RS) end, RS0, Ws), 429 Style = wings_pref:get_value(proxy_shaded_edge_style), 430 foldl(fun(D,RS) -> render_wire_object(D, Style, RS) end, RS1, PWs). 431 432render_wire_object(#dlo{drag={matrix,_,_,Matrix}}=D, PStyle, RS0) -> 433 gl:pushMatrix(), 434 gl:multMatrixf(Matrix), 435 RS1 = render_wire_object_1(D, PStyle, RS0), 436 gl:popMatrix(), 437 RS1; 438render_wire_object(D, PStyle, RS) -> 439 render_wire_object_1(D, PStyle, RS). 440 441render_wire_object_1(#dlo{mirror=none, edges=Edges, proxy=false}, _, RS) -> 442 wings_dl:call(Edges, RS); 443render_wire_object_1(#dlo{mirror=Matrix, edges=Edges, proxy=false}, _, RS0) -> 444 RS1 = wings_dl:call(Edges, RS0), 445 gl:frontFace(?GL_CW), 446 gl:pushMatrix(), 447 gl:multMatrixf(Matrix), 448 RS = wings_dl:call(Edges, RS1), 449 gl:popMatrix(), 450 gl:frontFace(?GL_CCW), 451 RS; 452render_wire_object_1(#dlo{mirror=none}=D, PStyle, RS) -> 453 wings_proxy:draw_smooth_edges(D, PStyle, RS); 454render_wire_object_1(#dlo{mirror=Matrix}=D, PStyle, RS0) -> 455 RS1 = wings_proxy:draw_smooth_edges(D, PStyle, RS0), 456 gl:frontFace(?GL_CW), 457 gl:pushMatrix(), 458 gl:multMatrixf(Matrix), 459 RS = wings_proxy:draw_smooth_edges(D, PStyle, RS1), 460 gl:popMatrix(), 461 gl:frontFace(?GL_CCW), 462 RS. 463 464split_objects([#dlo{src_we=We}=D|Dls], Open, Closed, Lights) when ?IS_ANY_LIGHT(We) -> 465 split_objects(Dls, Open, Closed, [D|Lights]); 466split_objects([#dlo{open=true}=D|Dls], Open, Closed, Lights) -> 467 split_objects(Dls, [D|Open], Closed, Lights); 468split_objects([#dlo{open=false}=D|Dls], Open, Closed, Lights) -> 469 split_objects(Dls, Open, [D|Closed], Lights); 470split_objects([], Open, Closed, Lights) -> 471 {Open, Closed, Lights}. 472 473split_wires([#dlo{src_we=We}|Dls], WOs, Show, Wires, Others, Proxis) when ?IS_LIGHT(We) -> 474 split_wires(Dls, WOs, Show, Wires, Others, Proxis); 475split_wires([#dlo{src_we=#we{id=Id}, proxy=Proxy}=D|Dls], WOs, Show, Wires, Others,Proxis) -> 476 case gb_sets:is_member(Id, WOs) of 477 true when Proxy -> split_wires(Dls, WOs, Show, Wires, Others, [D|Proxis]); 478 true -> split_wires(Dls, WOs, Show, [D|Wires], Others,Proxis); 479 false when Proxy -> split_wires(Dls, WOs, Show, Wires, Others,Proxis); 480 false when Show -> split_wires(Dls, WOs, Show, Wires, [D|Others], Proxis); 481 false -> split_wires(Dls, WOs, Show, Wires, Others,Proxis) 482 end; 483split_wires([], _, _, Ws, Os, Ps) -> 484 {Ws, Os, Ps}. 485 486render_sel_highlight(Dls, SelMode, false, PM, #{}=RS0) -> 487 gl:disable(?GL_POLYGON_OFFSET_LINE), 488 gl:disable(?GL_POLYGON_OFFSET_FILL), 489 gl:matrixMode(?GL_PROJECTION), 490 gl:pushMatrix(), 491 non_polygon_offset(1.0, PM), 492 gl:matrixMode(?GL_MODELVIEW), 493 gl:depthFunc(?GL_LEQUAL), 494 #{} = RS1 = foldl(fun(D, RS) -> render_sel(D, SelMode, false, RS) end, RS0, Dls), 495 #{} = RS2 = foldl(fun(D, RS) -> render_sel(D, SelMode, true, RS) end, RS1, Dls), 496 gl:matrixMode(?GL_PROJECTION), 497 gl:popMatrix(), 498 gl:depthFunc(?GL_LESS), 499 gl:matrixMode(?GL_MODELVIEW), 500 %% arbitrary placement in the grand scheme of things 501 foldl(fun(D, RS) -> wings_plugin:draw(plain,D,SelMode,RS) end, RS2, Dls); 502render_sel_highlight(Dls, SelMode, true, _PM, RS0) -> 503 RS1 = foldl(fun(D, RS) -> render_sel(D, SelMode, true, RS) end, RS0, Dls), 504 gl:depthFunc(?GL_LESS), 505 %% arbitrary placement in the grand scheme of things 506 foldl(fun(D, RS) -> wings_plugin:draw(smooth,D,none,RS) end, RS1, Dls). 507 508render_sel(#dlo{drag={matrix,_,_,Matrix}}=D, Mode, Sel, RS0) -> 509 gl:pushMatrix(), 510 gl:multMatrixf(Matrix), 511 RS = render_sel_1(D, Mode, Sel, RS0), 512 gl:popMatrix(), 513 RS; 514render_sel(D, Mode, Sel, RS) -> 515 render_sel_1(D, Mode, Sel, RS). 516 517render_sel_1(#dlo{mirror=none}=D, Mode, Sel, RS) -> 518 render_sel_2(D, Mode, Sel, RS); 519render_sel_1(#dlo{mirror=Matrix}=D, Mode, Sel, RS0) -> 520 RS1 = render_sel_2(D, Mode, Sel, RS0), 521 gl:frontFace(?GL_CW), 522 gl:pushMatrix(), 523 gl:multMatrixf(Matrix), 524 RS = render_sel_2(D, Mode, Sel, RS1), 525 gl:popMatrix(), 526 gl:frontFace(?GL_CCW), 527 RS. 528 529render_sel_2(#dlo{}=D, SelMode, false, RS0) -> 530 RS1 = draw_hard_edges(D, SelMode, RS0), 531 RS2 = draw_vertices(D, SelMode, RS1), 532 draw_normals(D, RS2); 533render_sel_2(#dlo{sel=none, orig_sel=none, hilite=none}, _SelMode, _, RS0) -> 534 RS0; 535render_sel_2(#dlo{src_we=We}=D, _SelMode, true, RS0) -> 536 RS = case wire(We) of 537 true -> 538 gl:disable(?GL_CULL_FACE), 539 #{} = RS1 = draw_orig_sel(D, RS0), 540 #{} = RS2 = draw_sel(D, RS1), 541 gl:enable(?GL_CULL_FACE), 542 RS2; 543 false -> 544 #{} = RS1 = draw_orig_sel(D, RS0), 545 draw_sel(D, RS1) 546 end, 547 draw_hilite(D, RS). 548 549wire(#we{id=Id}) -> 550 W = wings_wm:get_prop(wireframed_objects), 551 gb_sets:is_member(Id, W). 552 553draw_sel(#dlo{sel=none}, RS) -> RS; 554draw_sel(#dlo{sel=SelDlist,src_sel={edge,_}}, RS0) -> 555 gl:lineWidth(float(wings_pref:get_value(selected_edge_width))), 556 RS = sel_color(RS0), 557 wings_dl:call(SelDlist, RS); 558draw_sel(#dlo{sel=SelDlist,src_sel={vertex,_}}, RS0) -> 559 gl:pointSize(wings_pref:get_value(selected_vertex_size)), 560 RS = sel_color(RS0), 561 wings_dl:call(SelDlist, RS); 562draw_sel(#dlo{open=Open,sel=SelDlist}, RS0) -> 563 RS1 = sel_color(RS0), 564 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_FILL), 565 gl:enable(?GL_POLYGON_OFFSET_FILL), 566 polygonOffset(1.0), 567 %Stippled selection style. 568 gl:enable(?GL_POLYGON_STIPPLE), 569 RS = draw_face_sel(Open, SelDlist, RS1), 570 gl:disable(?GL_POLYGON_STIPPLE), 571 gl:disable(?GL_POLYGON_OFFSET_FILL), 572 RS. 573 574draw_face_sel(true, SelDlist, RS0) -> 575 case wings_pref:get_value(show_backfaces) of 576 true -> 577 gl:disable(?GL_CULL_FACE), 578 RS = wings_dl:call(SelDlist, RS0), 579 gl:enable(?GL_CULL_FACE), 580 RS; 581 _ -> 582 wings_dl:call(SelDlist, RS0) 583 end; 584draw_face_sel(false, SelDlist, RS) -> 585 wings_dl:call(SelDlist, RS). 586 587sel_color(RS0) -> 588 gl:color3fv(wings_pref:get_value(selected_color)), 589 RS0. 590 591draw_vertices(#dlo{src_we=#we{perm=P},vs=VsDlist}, vertex, RS0) when ?IS_SELECTABLE(P) -> 592 {R,G,B} = wings_pref:get_value(vertex_color), 593 Size = wings_pref:get_value(vertex_size), 594 gl:pointSize(Size), 595 gl:color3f(R,G,B), 596 wings_dl:call(VsDlist, RS0); 597draw_vertices(_, _, RS) -> RS. 598 599draw_hilite(#dlo{hilite=none}, RS) -> RS; 600draw_hilite(#dlo{hilite={_Mode,DL}}, RS) -> 601 wings_dl:call(DL, RS). 602 603draw_orig_sel_fun(Mode, DlistSel) -> 604 {R,G,B} = wings_pref:get_value(selected_color), 605 SelColor = {R,G,B,0.5}, 606 case Mode of 607 vertex -> 608 PointSize = wings_pref:get_value(selected_vertex_size)*2, 609 fun(RS0) -> 610 gl:pointSize(PointSize), 611 gl:enable(?GL_BLEND), 612 gl:blendFunc(?GL_SRC_ALPHA, ?GL_ONE_MINUS_SRC_ALPHA), 613 gl:color4fv(SelColor), 614 RS = wings_dl:call(DlistSel, RS0), 615 gl:disable(?GL_BLEND), 616 RS 617 end; 618 edge -> 619 LineWidth = wings_pref:get_value(selected_edge_width)*2.0, 620 fun(RS0) -> 621 gl:lineWidth(LineWidth), 622 gl:enable(?GL_BLEND), 623 gl:blendFunc(?GL_SRC_ALPHA, ?GL_ONE_MINUS_SRC_ALPHA), 624 gl:color4fv(SelColor), 625 RS = wings_dl:call(DlistSel, RS0), 626 gl:disable(?GL_BLEND), 627 RS 628 end; 629 _ -> 630 fun(RS0) -> 631 gl:enable(?GL_BLEND), 632 gl:blendFunc(?GL_SRC_ALPHA, ?GL_ONE_MINUS_SRC_ALPHA), 633 gl:color4fv(SelColor), 634 gl:enable(?GL_POLYGON_OFFSET_FILL), 635 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_FILL), 636 polygonOffset(1.0), 637 RS = wings_dl:call(DlistSel, RS0), 638 gl:disable(?GL_POLYGON_OFFSET_FILL), 639 RS 640 end 641 end. 642 643draw_orig_sel(#dlo{orig_sel=Dlist}, RS) -> 644 wings_dl:call(Dlist, RS). 645 646draw_hard_edges(#dlo{hard=none}, _, RS) -> RS; 647draw_hard_edges(#dlo{hard=Hard}, SelMode, RS) -> 648 gl:lineWidth(hard_edge_width(SelMode)), 649 gl:color3fv(wings_pref:get_value(hard_edge_color)), 650 wings_dl:call(Hard, RS). 651 652draw_normals(#dlo{normals=none}, RS) -> RS; 653draw_normals(#dlo{normals=Ns}, RS) -> 654 gl:color3f(0.0, 0.0, 1.0), 655 gl:lineWidth(float(wings_pref:get_value(normal_vector_width))), 656 wings_dl:call(Ns, RS). 657 658edge_width(edge) -> float(wings_pref:get_value(edge_width)); 659edge_width(_) -> 1.0. 660 661hard_edge_width(edge) -> float(wings_pref:get_value(hard_edge_width)); 662hard_edge_width(_) -> max(wings_pref:get_value(hard_edge_width) - 1.0, 1.0). 663 664draw_background(MM) -> 665 case wings_wm:is_geom() of 666 false -> 667 ignore; 668 true -> 669 wings_pref:get_value(show_bg) andalso draw_background_1(MM) 670 end. 671 672draw_background_1(MM) -> 673 gl:disable(?GL_CULL_FACE), 674 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_FILL), 675 gl:depthFunc(?GL_LEQUAL), 676 gl:matrixMode(?GL_PROJECTION), 677 gl:pushMatrix(), 678 load_perspectiv(), 679 RS0 = #{ws_eyepoint => e3d_mat:mul_point(e3d_transform:inv_matrix(MM), {0.0,0.0,0.0}), 680 view_from_world => MM}, 681 682 Update = fun(_) -> 683 #{size:=NoFs, tris:=Data} = wings_shapes:tri_cube(#{}), 684 D = fun(RS1) -> 685 RS = wings_shaders:set_uloc(bg_blur, wings_pref:get_value(show_bg_blur), RS1), 686 gl:drawArrays(?GL_TRIANGLES, 0, NoFs*3), 687 RS 688 end, 689 wings_vbo:new(D, Data) 690 end, 691 RS = wings_shaders:use_prog(background, RS0), 692 wings_dl:draw(background, ignore, Update, RS), 693 694 %% Reset 695 gl:popMatrix(), 696 gl:matrixMode(?GL_MODELVIEW), 697 gl:depthFunc(?GL_LESS), 698 wings_shaders:use_prog(0, RS), 699 ok. 700 701load_perspectiv() -> 702 {W,H} = wings_wm:win_size(), 703 Aspect = W/H, 704 #view{fov=Fov,hither=Hither,yon=Yon} = wings_view:current(), 705 TP = e3d_transform:perspective(Fov, Aspect, Hither, Yon), 706 gl:loadMatrixd(e3d_transform:matrix(TP)). 707 708ground_and_axes(View, PM,MM, RS0) -> 709 Axes = wings_wm:get_prop(show_axes), 710 RS1 = draw_axes(RS0, Axes, PM, MM, View), 711 groundplane(RS1, View, PM, MM). 712 713draw_axes(RS0, false, _, _, _) -> 714 wings_dl:draw(axes, none, fun(_) -> none end, RS0); 715draw_axes(RS0, _Show, PM, MM, View) -> 716 Yon = axis_size(RS0, View), 717 Key = axis_data([{1,x_color,neg_x_color}, 718 {2,y_color,neg_y_color}, 719 {3,z_color,neg_z_color}], 720 Yon), 721 Update = fun(Data) -> 722 D = fun(RS) -> 723 gl:lineWidth(2.1), 724 gl:drawArrays(?GL_LINES, 0, 3*4), 725 RS 726 end, 727 wings_vbo:new(D, Data, [color,vertex]) 728 end, 729 %% io:format("~p: depth_test ~p ~p~n", [?LINE, gl:isEnabled(?GL_DEPTH_TEST)==1, hd(gl:getIntegerv(?GL_DEPTH_FUNC))]), 730 RS1 = wings_dl:draw(axes, Key, Update, RS0), 731 axis_letters(RS1, PM, MM, Yon). 732 733axis_size(#{ws_eyepoint:=Eye}, #view{yon=Yon, distance=Dist0}) -> 734 case wings_pref:get_value(constrain_axes) of 735 true -> max((abs(element(2,Eye))+Dist0)*2, 25.0); %% As calculated in shader 736 false -> Yon 737 end. 738 739axis_data([{I,PosKey,NegKey}|T], Yon) -> 740 Pos = wings_pref:get_value(PosKey), 741 Neg = wings_pref:get_value(NegKey), 742 A0 = {0.0,0.0,0.0}, 743 A = setelement(I, A0, Yon), 744 B = setelement(I, A0, -Yon), 745 [Pos,A0,Pos,A,Neg,A0,Neg,B|axis_data(T, Yon)]; 746axis_data([], _) -> []. 747 748axis_letters(RS, TPM, TMM, Yon0) -> 749 ViewPort = wings_wm:viewport(), 750 gl:matrixMode(?GL_PROJECTION), 751 gl:loadIdentity(), 752 {_,_,W,H} = ViewPort, 753 Ortho = e3d_transform:ortho(0.0, float(W), float(H), 0.0, -1.0, 1.0), 754 gl:loadMatrixd(e3d_transform:matrix(Ortho)), 755 gl:matrixMode(?GL_MODELVIEW), 756 gl:loadIdentity(), 757 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_FILL), 758 PM = e3d_transform:matrix(TPM), 759 MM = e3d_transform:matrix(TMM), 760 Start = {0.0,0.0,0.0}, 761 Origin = proj(Start, MM, PM), 762 Info = {Start,Origin,MM,PM,ViewPort}, 763 Yon = Yon0 * 1.2, 764 axis_letter_1(1, Yon, axisx, x_color, Info), 765 axis_letter_1(2, Yon, axisy, y_color, Info), 766 axis_letter_1(3, Yon, axisz, z_color, Info), 767 RS. 768 769axis_letter_1(I, Yon, Char, Color0, {Start,{Ox,Oy,_,Ow},MM,PM,Viewport}) -> 770 Color = wings_pref:get_value(Color0), 771 wings_io:set_color(Color), 772 End = setelement(I, Start, Yon), 773 {Px,Py,_,Pw} = proj(End, MM, PM), 774 NegPw = -Pw, 775 if 776 NegPw < Px, Px < Pw, NegPw < Py, Py < Pw -> 777 show_letter(Px, Py, Pw, Char, Viewport); 778 true -> 779 clip(Ox, Oy, Ow, Px, Py, Pw, Char, Viewport) 780 end. 781 782show_camera_image_plane() -> 783 case wings_wm:get_prop(show_cam_imageplane) of 784 false -> 785 ok; 786 true -> 787 {WinW,WinH} = wings_wm:win_size(), 788 CamW = wings_pref:get_value(negative_width), 789 CamH = wings_pref:get_value(negative_height), 790 AspRatio = CamW/CamH, 791 %% it's used only the height as reference because view horizon changes only for height variation 792 {W,H} = {round(WinH*AspRatio)/2, WinH/2}, 793 794 X1 = (WinW/2.0)-W+5.0, 795 Y1 = (WinH/2.0)-H+5.0, 796 X2 = (WinW/2.0)+W-5.0, 797 Y2 = (WinH/2.0)+H-5.0, 798 799 Quads = [{X1,Y1,0.0},{X2,Y1,0.0}, % top 800 {WinW*1.0,0.0,0.0},{0.0,0.0,0.0}, 801 {X1,Y1,0.0},{0.0,0.0,0.0}, % left 802 {0.0,WinH*1.0,0.0},{X1,Y2,0.0}, 803 {X1,Y2,0.0},{0.0,WinH*1.0,0.0}, % bottom 804 {WinW*1.0,WinH*1.0,0.0},{X2*1.0,Y2,0.0}, 805 {X2*1.0,Y2,0.0},{WinW*1.0,WinH*1.0,0.0}, % right 806 {WinW*1.0,0.0,0.0},{X2,Y1,0.0}], 807 Poly = << <<X:?F32,Y:?F32,Z:?F32>> || {X,Y,Z} <- Quads >>, 808 Update = fun draw_camera_image_plane/1, 809 wings_dl:draw(draw_cam_imageplane, {Poly,{X1,Y1,X2,Y2}}, Update, #{}) 810 end. 811 812draw_camera_image_plane({Poly,{X1,Y1,X2,Y2}}) -> 813 NoVs = byte_size(Poly) div 12, 814 Draw = 815 fun(RS) -> 816 wings_io:ortho_setup(), 817 gl:enable(?GL_BLEND), 818 gl:blendFunc(?GL_SRC_ALPHA, ?GL_ONE_MINUS_SRC_ALPHA), 819 gl:color4f(0.0, 0.4, 0.8, 0.5), 820 gl:drawArrays(?GL_QUADS, 0, NoVs), 821 gl:color3f(0.0, 0.4, 0.8), 822 gl:lineWidth(2.0), 823 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_LINE), 824 gl:rectf(X2, Y1, X1, Y2), 825 gl:flush(), 826 RS 827 end, 828 wings_vbo:new(Draw, Poly). 829 830clip(Ox, Oy, Ow, Px, Py, Pw, Char, Viewport) -> 831 AxisRay = line(Ox, Oy, Px, Py), 832 NegOw = -Ow, 833 Lines = [line(NegOw, NegOw, Ow, NegOw),line(NegOw, Ow, Ow, Ow), 834 line(NegOw, NegOw, NegOw, Ow),line(Ow, NegOw, Ow, Ow)], 835 case clip_1(AxisRay, Lines, {Ow,Pw}) of 836 none -> ok; 837 {X,Y,W} -> show_letter(X, Y, W, Char, Viewport) 838 end. 839 840clip_1({O1,D1}=Axis, [{O2,D2}|Lines], {Ow,_}=W) -> 841 E = 1.0E-6, 842 case {pdot(D1, D2),pdot(D2, D1)} of 843 {Z1,Z2} when abs(Z1) < E; abs(Z2) < E -> 844 clip_1(Axis, Lines, W); 845 {Div1,Div2} -> 846 S = pdot(sub(O2, O1), D2)/Div1, 847 T = pdot(sub(O1, O2), D1)/Div2, 848 if 849 S < 0.0; T < 0.0; T > 1.0 -> 850 clip_1(Axis, Lines, W); 851 true -> 852 {X,Y} = add_prod(O1, D1, S), 853 {X,Y,Ow} 854 end 855 end; 856clip_1(_, [], _W) -> none. 857 858show_letter(X0, Y0, W, Char, {_,_,Vw,Vh}) -> 859 PosX = trunc((0.5*X0/W+0.5)*(Vw-20) + 10), 860 X = max(5, min(Vw-20, PosX)), 861 Y = max(30, min(Vh-20, Vh - trunc((0.5*Y0/W+0.5)*(Vh-16) - 1))), 862 axis_text(X, Y, Char). 863 864axis_text(X, Y, C) -> 865 wings_text:render(X, Y, [C]). 866 867proj({X0,Y0,Z0}, MM, PM) -> 868 e3d_mat:mul(PM, e3d_mat:mul(MM, {X0,Y0,Z0,1.0})). 869 870line(Ox, Oy, Px, Py) -> {{Ox,Oy},{Px-Ox,Py-Oy}}. 871 872pdot({X1,Y1}, {X2,Y2}) when is_float(X1), is_float(Y1) -> 873 Y1*X2-X1*Y2. 874 875sub({X1,Y1}, {X2,Y2}) -> 876 {X1-X2,Y1-Y2}. 877 878add_prod({X1,Y1}, {X2,Y2}, S) when is_float(S) -> 879 {S*X2+X1,S*Y2+Y1}. 880 881groundplane(RS0, #view{along_axis=Along, distance=Dist0}=View, PM, MM) -> 882 Show = wings_wm:get_prop(show_groundplane) 883 orelse (wings_pref:get_value(force_show_along_grid) 884 andalso Along =/= none), 885 Eye = maps:get(ws_eyepoint, RS0), 886 Scale = grid_scale(Eye, Dist0, Along), 887 case Show of 888 false -> RS0; 889 true -> draw_grid(View, PM, MM, Along, Scale, RS0) 890 end. 891 892-spec grid_scale(Eye::e3d_vec:point(), Dist::float(), ViewAlong::atom()) -> 893 {InvScale::float(), InvScale10::float(), Alpha1::float(), Alpha2::float()}. 894grid_scale({_,Y,_}, Dist0, Along) -> 895 Dist = case Along of 896 none -> max(abs(Dist0), abs(Y)); 897 _ -> Dist0 898 end, 899 Calc = fun(Len) -> 900 if Len > 10.0 -> 901 Exp = trunc(math:log(max(1.0, Len))/math:log(10))-1, 902 max(trunc(math:pow(10.0,Exp))*1.0, 1.0); 903 Len > 1.0 -> 0.1; 904 Len > 0.1 -> 0.01; 905 true -> 0.001 906 end 907 end, 908 Res = Calc(Dist), 909 Inc = Calc(Dist*2.0), %% Start blending when 50% distance covered 910 if 911 Inc > Res -> %% Blend in new lines 912 Blend = min(0.8,max(0.1, 2*(1.0 - Dist/(Inc*10)))), 913 %% io:format("~.3f ~.3f ~.3f ~.3f~n", [Dist, Inc, Blend, (abs(Y)+Dist0)*2]), 914 {1/Res, 1/Inc, Blend, 1.0}; 915 true -> %% Make every 10th stronger 916 {1/Res, 0.1/Res, 1.0, 1.0} 917 end. 918 919 920draw_grid(#view{origin=Origin, distance=Dist}, PM, MM, Along, Scale, RS0) -> 921 wings_io:ortho_setup(), 922 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_FILL), 923 gl:enable(?GL_BLEND), 924 gl:enable(?GL_DEPTH_TEST), 925 gl:disable(?GL_CULL_FACE), 926 gl:blendFunc(?GL_SRC_ALPHA, ?GL_ONE_MINUS_SRC_ALPHA), 927 Color = wings_pref:get_value(grid_color), 928 RS1 = wings_shaders:use_prog(grid, RS0), 929 RS2 = wings_shaders:set_uloc(proj, e3d_transform:matrix(PM), RS1), 930 RS3 = wings_shaders:set_uloc(view, e3d_transform:matrix(MM), RS2), 931 RS4 = wings_shaders:set_uloc(ws_origin, Origin, RS3), 932 RS5 = wings_shaders:set_uloc(dist, Dist, RS4), 933 RS6 = wings_shaders:set_uloc(scale, Scale, RS5), 934 RS7 = wings_shaders:set_uloc(color, Color, RS6), 935 RS8 = wings_shaders:set_uloc(along, along_axis(Along), RS7), 936 {_,_,W,H} = wings_wm:viewport(), 937 gl:recti(0, 0, W, H), 938 RS = wings_shaders:use_prog(0, RS8), 939 show_scale(W,H,1/element(1,Scale)), 940 %% Reset state.. 941 gl:enable(?GL_DEPTH_TEST), 942 wings_view:load_matrices(true), 943 RS. 944 945along_axis(none) -> 0; 946along_axis(x) -> 1; 947along_axis(y) -> 2; 948along_axis(z) -> 3. 949 950 951show_scale(W, H, Scale) -> 952 ScaleStr = float_to_list(float(Scale),[{decimals, 4}, compact]), 953 StrScale = ?__(1,"Grid Scale: x")++ScaleStr, 954 X = W-wings_text:width(StrScale)-10, 955 wings_io:info(X, H-18, StrScale). 956 957show_saved_bb(St) -> 958 Key = get_saved_bb_key(St), 959 Update = fun update_saved_bb/1, 960 wings_dl:draw(saved_bb, Key, Update, #{}). 961 962get_saved_bb_key(#st{bb=BB}) -> 963 case {wings_pref:get_value(show_bb),BB} of 964 {true,[A,B]} -> 965 Color = wings_pref:get_value(active_vector_color), 966 {A,B,Color}; 967 {_,_} -> 968 none 969 end. 970 971update_saved_bb({{X1,Y1,Z1},{X2,Y2,Z2},Color}) -> 972 %% 10 vertices in a line strip. 973 Data = [{X1,Y1,Z1}, 974 {X2,Y1,Z1}, 975 {X2,Y2,Z1}, 976 {X1,Y2,Z1}, 977 {X1,Y1,Z1}, 978 {X1,Y1,Z2}, 979 {X2,Y1,Z2}, 980 {X2,Y2,Z2}, 981 {X1,Y2,Z2}, 982 {X1,Y1,Z2}, 983 %% 6 vertices / 3 lines 984 {X1,Y2,Z1}, 985 {X1,Y2,Z2}, 986 {X2,Y2,Z1}, 987 {X2,Y2,Z2}, 988 {X2,Y1,Z1}, 989 {X2,Y1,Z2}], 990 D = fun(RS) -> 991 gl:enable(?GL_LINE_STIPPLE), 992 gl:lineStipple(4, 2#1110111011101110), 993 gl:color3fv(Color), 994 gl:drawArrays(?GL_LINE_STRIP, 0, 10), 995 gl:drawArrays(?GL_LINES, 10, 6), 996 gl:disable(?GL_LINE_STIPPLE), 997 RS 998 end, 999 wings_vbo:new(D, Data). 1000 1001show_bb_center(St) -> 1002 Key = get_bb_center_key(St), 1003 Update = fun update_bb_center/1, 1004 wings_dl:draw(saved_bb_center, Key, Update, #{}). 1005 1006get_bb_center_key(#st{bb=BB}) -> 1007 case {wings_pref:get_value(show_bb_center),BB} of 1008 {true,[_,_]} -> 1009 Center = e3d_vec:average(BB), 1010 Color = wings_pref:get_value(active_vector_color), 1011 {Center,Color}; 1012 {_,_} -> 1013 none 1014 end. 1015 1016update_bb_center({{Cx,Cy,Cz}=Center,Color}) -> 1017 Data = [Center, 1018 {Cx,Cy+0.2,Cz}, 1019 {Cx,Cy-0.2,Cz}, 1020 {Cx+0.2,Cy,Cz}, 1021 {Cx-0.2,Cy,Cz}, 1022 {Cx,Cy,Cz+0.2}, 1023 {Cx,Cy,Cz-0.2}], 1024 D = fun(RS) -> 1025 gl:color3fv(Color), 1026 gl:pointSize(8.0), 1027 gl:drawArrays(?GL_POINTS, 0, 1), 1028 gl:drawArrays(?GL_LINES, 1, 6), 1029 RS 1030 end, 1031 wings_vbo:new(D, Data). 1032 1033mini_axis_icon(View, MM) -> 1034 case mini_axis_icon_key(View) of 1035 none -> ok; 1036 Key -> draw_mini_axis_icon(Key, MM) 1037 end. 1038 1039draw_mini_axis_icon(Key, MM) -> 1040 {W,H} = wings_wm:win_size(), 1041 Ratio = W/H, 1042 Matrix0 = e3d_transform:matrix(MM), 1043 Matrix1 = setelement(15, Matrix0, 0.0), 1044 Matrix2 = setelement(14, Matrix1, -1.0+0.11), 1045 Matrix = setelement(13, Matrix2, 0.11-Ratio), 1046 gl:pushAttrib(?GL_ALL_ATTRIB_BITS), 1047 gl:matrixMode(?GL_PROJECTION), 1048 gl:pushMatrix(), 1049 gl:loadIdentity(), 1050 Ortho = e3d_transform:ortho(-Ratio, Ratio, -1.0, 1.0, 0.00001, 10000000.0), 1051 gl:loadMatrixd(e3d_transform:matrix(Ortho)), 1052 gl:matrixMode(?GL_MODELVIEW), 1053 gl:pushMatrix(), 1054 gl:loadMatrixd(Matrix), 1055 1056 Update = fun update_mini_axis_icon/1, 1057 wings_dl:draw(mini_axis_icon, Key, Update, #{}), 1058 1059 gl:popMatrix(), 1060 gl:matrixMode(?GL_PROJECTION), 1061 gl:popMatrix(), 1062 gl:matrixMode(?GL_MODELVIEW), 1063 gl:popAttrib(). 1064 1065mini_axis_icon_key(#view{along_axis=Along}) -> 1066 case wings_pref:get_value(mini_axis) of 1067 false -> 1068 none; 1069 true -> 1070 X = wings_pref:get_value(x_color), 1071 Y = wings_pref:get_value(y_color), 1072 Z = wings_pref:get_value(z_color), 1073 {Along,{X,Y,Z}} 1074 end. 1075 1076update_mini_axis_icon({Along,{X,Y,Z}}) -> 1077 Arrows = mini_axis_arrows(Along, X, Y, Z), 1078 Data = [X,{0.0,0.0,0.0}, %X Axis 1079 X,{0.1,0.0,0.0}, 1080 Y,{0.0,0.0,0.0}, %Y Axis 1081 Y,{0.0,0.1,0.0}, 1082 Z,{0.0,0.0,0.0}, %Z Axis 1083 Z,{0.0,0.0,0.1}|Arrows], 1084 N = case Along of 1085 none -> 3*2 + 3*4; 1086 _ -> 3*2 + 2*4 1087 end, 1088 D = fun(RS) -> 1089 gl:drawArrays(?GL_LINES, 0, N), 1090 RS 1091 end, 1092 wings_vbo:new(D, Data, [color,vertex]). 1093 1094mini_axis_arrows(Along, X, Y, Z) -> 1095 PA = 0.08, 1096 PB = 0.01, 1097 case Along of 1098 none -> 1099 %% X Arrows 1100 [X,{PA,0.0,-PB}, 1101 X,{0.1,0.0,0.0}, 1102 X,{PA,0.0,PB}, 1103 X,{0.1,0.0,0.0}, 1104 %% Y Arrows 1105 Y,{-PB,PA,0.0}, 1106 Y,{0.0,0.1,0.0}, 1107 Y,{PB,PA,0.0}, 1108 Y,{0.0,0.1,0.0}, 1109 %% Z Arrows 1110 Z,{-PB,0.0,PA}, 1111 Z,{0.0,0.0,0.1}, 1112 Z,{PB,0.0,PA}, 1113 Z,{0.0,0.0,0.1}]; 1114 x -> 1115 %% Y Arrows 1116 [Y,{0.0,PA,-PB}, 1117 Y,{0.0,0.1,0.0}, 1118 Y,{0.0,PA,PB}, 1119 Y,{0.0,0.1,0.0}, 1120 %% Z Arrows 1121 Z,{0.0,-PB,PA}, 1122 Z,{0.0,0.0,0.1}, 1123 Z,{0.0,PB,PA}, 1124 Z,{0.0,0.0,0.1}]; 1125 y -> 1126 %% X Arrows 1127 [X,{PA,0.0,-PB}, 1128 X,{0.1,0.0,0.0}, 1129 X,{PA,0.0,PB}, 1130 X,{0.1,0.0,0.0}, 1131 %% Z Arrows 1132 Z,{-PB,0.0,PA}, 1133 Z,{0.0,0.0,0.1}, 1134 Z,{PB,0.0,PA}, 1135 Z,{0.0,0.0,0.1}]; 1136 z -> 1137 %% X Arrows 1138 [X,{PA,-PB,0.0}, 1139 X,{0.1,0.0,0.0}, 1140 X,{PA,PB,0.0}, 1141 X,{0.1,0.0,0.0}, 1142 %% Y Arrows 1143 Y,{-PB,PA,0.0}, 1144 Y,{0.0,0.1,0.0}, 1145 Y,{PB,PA,0.0}, 1146 Y,{0.0,0.1,0.0}] 1147 end. 1148 1149user_clipping_planes(on) -> 1150 case wings_wm:get_prop(clip_plane) of 1151 true -> 1152 {_Position,Direction = {X,Y,Z}} = wings_pref:get_value(last_axis), 1153 Expand = fun({X1,Y1,Z1}) -> [X1,Y1,Z1,0.0] end, 1154 draw_clip_disk(Direction, Expand), 1155 gl:clipPlane(?GL_CLIP_PLANE0, {X,Y,Z,0.0}), 1156 gl:enable(?GL_CLIP_PLANE0), 1157 gl:disable(?GL_CULL_FACE); 1158 false -> 1159 ok 1160 end; 1161user_clipping_planes(off) -> 1162 gl:disable(?GL_CLIP_PLANE0), 1163 gl:enable(?GL_CULL_FACE). 1164 1165draw_clip_disk(Direction, Expand) -> 1166 NZ = e3d_vec:norm(Direction), 1167 NX = e3d_vec:norm(e3d_vec:cross(NZ,{0.0,0.0,1.0})), 1168 NY = e3d_vec:cross(NX,NZ), 1169 Nx = Expand(NX), 1170 Ny = Expand(NY), 1171 Nz = Expand(NZ), 1172 Nw = [0.0,0.0,0.0,1.0], 1173 M = list_to_tuple(lists:append([Nx,Ny,Nz,Nw])), 1174 Rad = wings_pref:get_value(clip_plane_size), 1175 1176 gl:color3fv(wings_pref:get_value(clip_plane_color)), 1177 gl:pushMatrix(), 1178 gl:multMatrixd(M), 1179 1180 #{size:=Size, tris:=Tris} = wings_shapes:tri_disc(#{subd=>4, scale=> Rad, binary => true}), 1181 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_LINE), 1182 wings_vbo:draw(fun(_) -> gl:drawArrays(?GL_TRIANGLES, 0, Size*3) end, Tris), 1183 gl:polygonMode(?GL_FRONT_AND_BACK, ?GL_FILL), 1184 gl:popMatrix(). 1185