1%% 2%% wings_draw_setup.erl -- 3%% 4%% Setup and Create data binaries for drawing 5%% 6%% Copyright (c) 2010-2011 Dan Gudmundsson & Björn Gustavsson 7%% 8%% See the file "license.terms" for information on usage and redistribution 9%% of this file, and for a DISCLAIMER OF ALL WARRANTIES. 10%% 11%% $Id$ 12%% 13 14-module(wings_draw_setup). 15 16-export([we/3]). %% For plugins 17 18-export([work/2,smooth/2,prepare/3,prepare/4,flat_faces/2]). 19-export([enable_pointers/3,disable_pointers/2]). 20-export([face_vertex_count/1,has_active_color/1]). 21 22%% Used by wings_proxy. 23-export([create_vab/4,create_tangent_vab/5, 24 add_ts/5,add_tangents/3]). 25 26-export_type([face_map/0,face_tris/0,plan/0]). 27 28-define(NEED_OPENGL, 1). 29-include("wings.hrl"). 30 31-import(lists, [reverse/1,sort/1,foldl/3]). 32 33 34-type face_tris() :: {non_neg_integer(),non_neg_integer()}. 35-type face_map() :: array:array(face_tris()) | [face_tris()]. 36 37-type material_name() :: atom(). 38-type plan_type() :: 'color' | 'color_uv' | 'color_uv_tangent' 39 | 'plain' | 'uv' | 'uv_tangent'. 40-type plan() :: {plan_type(),[{material_name(), 41 [{wings_face:face_num(),wings_edge:edge_num()}]}]}. 42 43%%% 44%%% we(We, [Option], St) -> #vab{} See wings.hrl 45%%% Generates rendering buffers from a we, 46%%% reuses data if available. 47%%% Options are: 48%%% {smooth, true|false} default false 49%%% {subdiv, Level :: integer()} default 0 50%%% {attribs, undefined|plain|uv|color|color_uv} default undefined 51%%% undefined -> you get what is available and enabled in wings_prefs 52%%% plain -> only vertex positions and normal 53we(We, Options, St) -> 54 wings_dl:fold(fun(Dl, undefined) -> we_1(Dl, We, Options, St); 55 (_Dl, Res) -> Res 56 end, undefined). 57 58we_1(Dlo=#dlo{src_we=Orig=#we{id=Id}}, Curr=#we{id=Id}, Opt, St) -> 59 case Orig =:= Curr of 60 true -> we_2(Dlo, Opt, St); 61 false -> we_2(wings_draw:changed_we(Dlo,#dlo{src_we=Curr}), Opt, St) 62 end; 63we_1(_, _, _, _) -> 64 undefined. 65 66we_2(Dlo0, Opt, St) -> 67 Smooth = proplists:get_value(smooth, Opt, false), 68 Attrib = proplists:get_value(attribs, Opt, undefined), 69 Dlo1 = setup_vmirror(proplists:get_value(vmirror, Opt, undefined), Dlo0), 70 Dlo2 = setup_subdiv(proplists:get_value(subdiv, Opt, 0), Dlo1), 71 Dlo = check_attrib(Attrib, Dlo2), 72 #dlo{vab=Vab} = 73 case Smooth of 74 true -> smooth(Dlo, St, Attrib); 75 false -> work(Dlo, St, Attrib) 76 end, 77 Vab. 78 79setup_vmirror(undefined, Dlo) -> Dlo; 80setup_vmirror(_, Dlo=#dlo{src_we=#we{mirror=none}}) -> Dlo; 81setup_vmirror(_, #dlo{src_we=We}) -> 82 Mirrored = wings_we:freeze_mirror(We), 83 wings_draw:changed_we(#dlo{}, #dlo{src_we=Mirrored}). 84 85setup_subdiv(0, Dlo) -> Dlo; 86setup_subdiv(N, #dlo{src_we=We}) -> 87 SubDived = sub_divide(N, We), 88 wings_draw:changed_we(#dlo{}, #dlo{src_we=SubDived}). 89sub_divide(0, We) -> We; 90sub_divide(N, We) -> 91 sub_divide(N-1, wings_subdiv:smooth(We)). 92 93check_attrib(undefined, Dlo) -> Dlo; 94check_attrib(_, Dlo = #dlo{vab=none}) -> Dlo; 95check_attrib(uv, Dlo = #dlo{vab = #vab{face_uv={_,_}, face_vc=none}}) -> Dlo; 96check_attrib(color, Dlo = #dlo{vab = #vab{face_vc={_,_}, face_uv=none}}) -> Dlo; 97check_attrib(color_uv, Dlo = #dlo{vab = #vab{face_vc={_,_}, face_uv={_,_}}}) -> Dlo; 98check_attrib(_, D) -> 99 D#dlo{vab=none}. %% Force rebuild 100 101%%% 102%%% Help functions to activate and disable buffer pointers. 103%%% 104 105has_active_color(#vab{face_vc=Color}) -> 106 Color =/= none. 107 108%% enable_pointers(#vab{}, [ExtraPointer], RS) -> 109%% ExtraPointer = face_normals | vertex_normals | colors | uvs | tangents 110%% Enable the vertex buffer pointer, and optionally other pointers. 111 112enable_pointers(#vab{id=Vbo,face_vs={Stride,BinVs}}=Vab, Extra, RS0) -> 113 gl:bindBuffer(?GL_ARRAY_BUFFER, Vbo), 114 gl:vertexPointer(3, ?GL_FLOAT, Stride, BinVs), 115 CS = foldl(fun(What,Acc) -> 116 case enable_pointer(What, Vab) of 117 ok -> Acc; 118 State -> [State|Acc] 119 end 120 end, [?GL_VERTEX_ARRAY], Extra), 121 OldCs = maps:get({vbo,Vbo}, RS0, []), 122 %io:format("Enable: ~p => ~p~n", [CS, CS -- OldCs]), 123 [enable_state(State) || State <- CS], 124 %io:format("Disable: ~p => ~p~n", [OldCs, OldCs -- CS]), 125 [disable_state(State) || State <- OldCs -- CS], 126 gl:bindBuffer(?GL_ARRAY_BUFFER, 0), 127 RS0#{{vbo,Vbo}=>CS}. 128 129%% disable_pointers(RS) 130%% Disable the active pointers 131 132disable_pointers(#vab{id=Vbo}, RS0) -> 133 OldCs = maps:get({vbo, Vbo}, RS0, []), 134 [disable_state(What) || What <- OldCs], 135 gl:bindBuffer(?GL_ARRAY_BUFFER, 0), 136 RS0#{{vbo, Vbo}=>[]}. 137 138enable_pointer(face_normals, #vab{face_fn={Stride,Ns}}) -> 139 gl:normalPointer(?GL_FLOAT, Stride, Ns), 140 ?GL_NORMAL_ARRAY; 141enable_pointer(vertex_normals, #vab{id=MainVbo,face_sn={vbo,Vbo}}) -> 142 gl:bindBuffer(?GL_ARRAY_BUFFER, Vbo), 143 gl:normalPointer(?GL_FLOAT, 0, 0), 144 gl:bindBuffer(?GL_ARRAY_BUFFER, MainVbo), 145 ?GL_NORMAL_ARRAY; 146enable_pointer(vertex_normals, #vab{face_sn={Stride,Ns}}) -> 147 %% Only used by wings_cc. 148 gl:normalPointer(?GL_FLOAT, Stride, Ns), 149 ?GL_NORMAL_ARRAY; 150enable_pointer(colors, #vab{face_vc=FaceCol}) -> 151 case FaceCol of 152 none -> 153 ok; 154 {Stride,Color} -> 155 gl:colorPointer(3, ?GL_FLOAT, Stride, Color), 156 ?GL_COLOR_ARRAY 157 end; 158enable_pointer(uvs, #vab{face_uv=FaceUV}) -> 159 case FaceUV of 160 none -> 161 ok; 162 {Stride,UV} -> 163 gl:texCoordPointer(2, ?GL_FLOAT, Stride, UV), 164 ?GL_TEXTURE_COORD_ARRAY 165 end; 166enable_pointer(tangents, #vab{face_ts=FaceTs}) -> 167 case FaceTs of 168 none -> 169 ok; 170 {Stride,Ts} -> 171 gl:vertexAttribPointer(?TANGENT_ATTR, 4, ?GL_FLOAT, 172 ?GL_FALSE, Stride, Ts), 173 {attrib, ?TANGENT_ATTR} 174 end. 175 176enable_state({attrib, Attr}) -> 177 gl:enableVertexAttribArray(Attr); 178enable_state(Attr) -> 179 gl:enableClientState(Attr). 180 181disable_state({attrib, Attr}) -> 182 gl:disableVertexAttribArray(Attr); 183disable_state(Attr) -> 184 gl:disableClientState(Attr). 185 186face_vertex_count(#dlo{vab=#vab{mat_map=[{_Mat,_Type,Start,Count}|_]}}) -> 187 Start+Count; 188face_vertex_count(#vab{mat_map=[{_Mat,_Type,Start,Count}|_]}) -> 189 Start+Count. 190 191%% Setup face_vs and face_fn and additional uv coords or vertex colors 192work(Dlo, St) -> 193 work(Dlo, St, undefined). 194 195work(#dlo{ns={_}}=D0, St, Attr) -> 196 D = wings_draw:update_normals(D0), 197 work(D, St, Attr); 198work(#dlo{vab=none,src_we=#we{fs=Ftab}}=D, St, Attr) -> 199 Prepared = prepare(gb_trees:to_list(Ftab), D, St, Attr), 200 flat_faces(Prepared, D); 201work(#dlo{vab=#vab{face_vs=none},src_we=#we{fs=Ftab}}=D, St, Attr) -> 202 Prepared = prepare(gb_trees:to_list(Ftab), D, St, Attr), 203 flat_faces(Prepared, D); 204work(#dlo{vab=#vab{face_fn=none}=Vab}=D, St, Attr) -> 205 %% Can this really happen? If it can, it happens infrequently, 206 %% so we don't have to handle it efficiently. 207 work(D#dlo{vab=Vab#vab{face_vs=none}}, St, Attr); 208work(D, _, _) -> D. 209 210%% Setup face_vs and face_sn and additional uv coords or vertex colors 211smooth(Dlo, St) -> 212 smooth(Dlo, St, undefined). 213 214smooth(#dlo{ns={_}}=D0, St, Attr) -> 215 D = wings_draw:update_normals(D0), 216 smooth(D, St, Attr); 217smooth(#dlo{vab=none}=D, St, Attr) -> 218 setup_smooth_normals(work(D, St, Attr)); 219smooth(#dlo{vab=#vab{face_vs=none}}=D, St, Attr) -> 220 setup_smooth_normals(work(D, St, Attr)); 221smooth(D=#dlo{vab=#vab{face_sn=none}}, _St, _) -> 222 setup_smooth_normals(D); 223smooth(D, _, _) -> D. 224 225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 226 227-spec flat_faces(plan(), #dlo{}) -> #dlo{}. 228 229flat_faces({plain,MatFaces}, D) -> 230 plain_flat_faces(MatFaces, D, 0, <<>>, [], []); 231flat_faces({uv,MatFaces}, D) -> 232 uv_flat_faces(MatFaces, D, 0, <<>>, [], []); 233flat_faces({uv_tangent,MatFaces}, D) -> 234 Z = e3d_vec:zero(), 235 Array = array:new([{default, {Z,Z}}]), 236 tangent_flat_faces(MatFaces, D, 0, <<>>, [], [], {Array, []}); 237flat_faces({color,MatFaces}, D) -> 238 col_flat_faces(MatFaces, D, 0, <<>>, [], []); 239flat_faces({color_uv,MatFaces}, D) -> 240 col_uv_faces(MatFaces, D, 0, <<>>, [], []); 241flat_faces({color_uv_tangent,MatFaces}, D) -> 242 Z = e3d_vec:zero(), 243 Array = array:new([{default, {Z,Z}}]), 244 col_tangent_faces(MatFaces, D, 0, <<>>, [], [], {Array, []}). 245 246plain_flat_faces([{Mat,Fs}|T], #dlo{ns=Ns}=D, Start0, Vs0, Fmap0, MatInfo0) -> 247 {Start,Vs,FaceMap} = flat_faces_1(Fs, Ns, Start0, Vs0, Fmap0), 248 MatInfo = [{Mat,?GL_TRIANGLES,Start0,Start-Start0}|MatInfo0], 249 plain_flat_faces(T, D, Start, Vs, FaceMap, MatInfo); 250plain_flat_faces([], D, _Start, Vs, FaceMap0, MatInfo) -> 251 FaceMap = array:from_orddict(sort(FaceMap0)), 252 Vab = create_vab([vertices,face_normals], Vs, FaceMap, MatInfo), 253 D#dlo{vab=Vab}. 254 255flat_faces_1([{Face,_}|Fs], Ns, Start, Vs, FaceMap) -> 256 case array:get(Face, Ns) of 257 [Normal|Pos =[_,_,_]] -> 258 flat_faces_1(Fs, Ns, Start+3, 259 add_tri(Vs, Normal, Pos), 260 [{Face,{Start,3}}|FaceMap]); 261 [Normal|Pos] -> 262 flat_faces_1(Fs, Ns, Start+6, 263 add_quad(Vs, Normal, Pos), 264 [{Face,{Start,6}}|FaceMap]); 265 {Normal,Faces,VsPos} -> 266 NoVs = length(Faces) * 3, 267 VsBin = add_poly(Vs, Normal, Faces, list_to_tuple(VsPos)), 268 flat_faces_1(Fs, Ns, NoVs+Start, 269 VsBin, [{Face,{Start,NoVs}}|FaceMap]) 270 end; 271flat_faces_1([], _, Start, Vs, FaceMap) -> 272 {Start,Vs,FaceMap}. 273 274uv_flat_faces([{Mat,Fs}|T], D, Start0, Vs0, Fmap0, MatInfo0) -> 275 {Start,Vs,FaceMap} = uv_flat_faces_1(Fs, D, Start0, Vs0, Fmap0), 276 MatInfo = [{Mat,?GL_TRIANGLES,Start0,Start-Start0}|MatInfo0], 277 uv_flat_faces(T, D, Start, Vs, FaceMap, MatInfo); 278uv_flat_faces([], D, _Start, Vs, FaceMap0, MatInfo) -> 279 FaceMap = array:from_orddict(sort(FaceMap0)), 280 Vab = create_vab([vertices,face_normals,uvs], Vs, FaceMap, MatInfo), 281 D#dlo{vab=Vab}. 282 283uv_flat_faces_1([{Face,Edge}|Fs], #dlo{ns=Ns,src_we=We}=D, Start, Vs, FaceMap) -> 284 UVs = wings_va:face_attr(uv, Face, Edge, We), 285 case array:get(Face, Ns) of 286 [Normal|Pos =[_,_,_]] -> 287 uv_flat_faces_1(Fs, D, Start+3, 288 add_tri(Vs, Normal, Pos, UVs), 289 [{Face,{Start,3}}|FaceMap]); 290 [Normal|Pos] -> 291 uv_flat_faces_1(Fs, D, Start+6, 292 add_quad(Vs, Normal, Pos, UVs), 293 [{Face,{Start,6}}|FaceMap]); 294 {Normal,Faces,VsPos} -> 295 NoVs = length(Faces) * 3, 296 VsBin = add_poly(Vs, Normal, Faces, 297 list_to_tuple(VsPos), list_to_tuple(UVs)), 298 uv_flat_faces_1(Fs, D, NoVs+Start, 299 VsBin, [{Face,{Start,NoVs}}|FaceMap]) 300 end; 301uv_flat_faces_1([], _, Start, Vs, FaceMap) -> 302 {Start,Vs,FaceMap}. 303 304%% Also needs uv's 305tangent_flat_faces([{Mat,Fs}|T], D, Start0, Vs0, Fmap0, MatInfo0, Ts0) -> 306 {Start,Vs,FaceMap,Ts} = tangent_flat_faces_1(Fs, D, Start0, Vs0, Fmap0, Ts0), 307 MatInfo = [{Mat,?GL_TRIANGLES,Start0,Start-Start0}|MatInfo0], 308 tangent_flat_faces(T, D, Start, Vs, FaceMap, MatInfo, Ts); 309tangent_flat_faces([], D, _Start, Vs, FaceMap0, MatInfo, {VsTs0, RevF2V}) -> 310 FaceMap = array:from_orddict(sort(FaceMap0)), 311 VsTs = array:map(fun(_V, {T,BT}) -> 312 {e3d_vec:norm(T),e3d_vec:norm(BT)} 313 end, VsTs0), 314 Data = add_tangents(lists:reverse(RevF2V), VsTs, Vs), 315 What = [vertices,face_normals,uvs], 316 Vab = create_tangent_vab(What, Vs, Data, FaceMap, MatInfo), 317 D#dlo{vab=Vab}. 318 319tangent_flat_faces_1([{Face,Edge}|Fs], #dlo{ns=Ns,src_we=We}=D, Start, Vs, FaceMap, Ts0) -> 320 UVs = wings_va:face_attr(uv, Face, Edge, We), 321 case array:get(Face, Ns) of 322 [Normal|Pos =[_,_,_]] -> 323 tangent_flat_faces_1(Fs, D, Start+3, 324 add_tri(Vs, Normal, Pos, UVs), 325 [{Face,{Start,3}}|FaceMap], 326 add_ts(Pos, UVs, Normal, 327 wings_face:vertices_ccw(Face, We), Ts0) 328 ); 329 [Normal|Pos] -> 330 tangent_flat_faces_1(Fs, D, Start+6, 331 add_quad(Vs, Normal, Pos, UVs), 332 [{Face,{Start,6}}|FaceMap], 333 add_ts(Pos, UVs, Normal, 334 wings_face:vertices_ccw(Face, We), Ts0)); 335 Info = {Normal,Faces,VsPos} -> 336 NoVs = length(Faces) * 3, 337 VsBin = add_poly(Vs, Normal, Faces, 338 list_to_tuple(VsPos), list_to_tuple(UVs)), 339 tangent_flat_faces_1(Fs, D, NoVs+Start, 340 VsBin, [{Face,{Start,NoVs}}|FaceMap], 341 add_ts(Info, UVs, Normal, 342 wings_face:vertices_ccw(Face, We), Ts0)) 343 end; 344tangent_flat_faces_1([], _, Start, Vs, FaceMap, Ts) -> 345 {Start,Vs,FaceMap,Ts}. 346 347 348col_flat_faces([{Mat,Fs}|T], D, Start0, Vs0, Fmap0, MatInfo0) -> 349 {Start,Vs,FaceMap} = col_flat_faces_1(Fs, D, Start0, Vs0, Fmap0), 350 MatInfo = [{Mat,?GL_TRIANGLES,Start0,Start-Start0}|MatInfo0], 351 col_flat_faces(T, D, Start, Vs, FaceMap, MatInfo); 352col_flat_faces([], D, _Start, Vs, FaceMap0, MatInfo) -> 353 FaceMap = array:from_orddict(sort(FaceMap0)), 354 Vab = create_vab([vertices,face_normals,colors], Vs, FaceMap, MatInfo), 355 D#dlo{vab=Vab}. 356 357col_flat_faces_1([{Face,Edge}|T], #dlo{ns=Ns,src_we=We}=D, Start, Vs0, Fmap0) -> 358 Cols = wings_va:face_attr(color, Face, Edge, We), 359 case array:get(Face, Ns) of 360 [Normal|Pos =[_,_,_]] -> 361 Vs = add_col_tri(Vs0, Normal, Pos, Cols), 362 Fmap = [{Face,{Start,3}}|Fmap0], 363 col_flat_faces_1(T, D, Start+3, Vs, Fmap); 364 [Normal|Pos] -> 365 Vs = add_col_quad(Vs0, Normal, Pos, Cols), 366 Fmap = [{Face,{Start,6}}|Fmap0], 367 col_flat_faces_1(T, D, Start+6, Vs, Fmap); 368 {Normal,Faces,VsPos} -> 369 NumVs = length(Faces) * 3, 370 Vs = add_col_poly(Vs0, Normal, Faces, 371 list_to_tuple(VsPos), list_to_tuple(Cols)), 372 Fmap = [{Face,{Start,NumVs}}|Fmap0], 373 col_flat_faces_1(T, D, Start+NumVs, Vs, Fmap) 374 end; 375col_flat_faces_1([], _, Start, Vs, Fmap) -> 376 {Start,Vs,Fmap}. 377 378col_uv_faces([{Mat,Fs}|T], D, Start0, Vs0, Fmap0, MatInfo0) -> 379 {Start,Vs,FaceMap} = col_uv_faces_1(Fs, D, Start0, Vs0, Fmap0), 380 MatInfo = [{Mat,?GL_TRIANGLES,Start0,Start-Start0}|MatInfo0], 381 col_uv_faces(T, D, Start, Vs, FaceMap, MatInfo); 382col_uv_faces([], D, _Start, Vs, FaceMap0, MatInfo) -> 383 FaceMap = array:from_orddict(sort(FaceMap0)), 384 Vab = create_vab([vertices,face_normals,colors,uvs], 385 Vs, FaceMap, MatInfo), 386 D#dlo{vab=Vab}. 387 388col_uv_faces_1([{Face,Edge}|Fs], #dlo{ns=Ns,src_we=We}=D, Start, Vs, FaceMap) -> 389 UVs = wings_va:face_attr([color|uv], Face, Edge, We), 390 case array:get(Face, Ns) of 391 [Normal|Pos =[_,_,_]] -> 392 col_uv_faces_1(Fs, D, Start+3, 393 add_col_uv_tri(Vs, Normal, Pos, UVs), 394 [{Face,{Start,3}}|FaceMap]); 395 [Normal|Pos] -> 396 col_uv_faces_1(Fs, D, Start+6, 397 add_col_uv_quad(Vs, Normal, Pos, UVs), 398 [{Face,{Start,6}}|FaceMap]); 399 {Normal,Faces,VsPos} -> 400 NoVs = length(Faces) * 3, 401 VsBin = add_col_uv_poly(Vs, Normal, Faces, 402 list_to_tuple(VsPos), list_to_tuple(UVs)), 403 col_uv_faces_1(Fs, D, NoVs+Start, 404 VsBin, [{Face,{Start,NoVs}}|FaceMap]) 405 end; 406col_uv_faces_1([], _, Start, Vs, FaceMap) -> 407 {Start,Vs,FaceMap}. 408 409%% Also needs uv's 410col_tangent_faces([{Mat,Fs}|T], D, Start0, Vs0, Fmap0, MatInfo0, Ts0) -> 411 {Start,Vs,FaceMap,Ts} = col_tangent_faces_1(Fs, D, Start0, Vs0, Fmap0, Ts0), 412 MatInfo = [{Mat,?GL_TRIANGLES,Start0,Start-Start0}|MatInfo0], 413 col_tangent_faces(T, D, Start, Vs, FaceMap, MatInfo, Ts); 414col_tangent_faces([], D, _Start, Vs, FaceMap0, MatInfo, {VsTs0, RevF2V}) -> 415 FaceMap = array:from_orddict(sort(FaceMap0)), 416 VsTs = array:map(fun(_V, {T,BT}) -> 417 {e3d_vec:norm(T),e3d_vec:norm(BT)} 418 end, VsTs0), 419 Data = add_tangents(lists:reverse(RevF2V), VsTs, Vs), 420 What = [vertices,face_normals,colors,uvs], 421 Vab = create_tangent_vab(What, Vs, Data, FaceMap, MatInfo), 422 D#dlo{vab=Vab}. 423 424col_tangent_faces_1([{Face,Edge}|Fs], #dlo{ns=Ns,src_we=We}=D, Start, Vs, FaceMap, Ts0) -> 425 UVs = wings_va:face_attr([color|uv], Face, Edge, We), 426 case array:get(Face, Ns) of 427 [Normal|Pos =[_,_,_]] -> 428 col_tangent_faces_1(Fs, D, Start+3, 429 add_col_uv_tri(Vs, Normal, Pos, UVs), 430 [{Face,{Start,3}}|FaceMap], 431 add_ts(Pos, [UV|| [_|UV] <- UVs], Normal, 432 wings_face:vertices_ccw(Face, We), Ts0)); 433 [Normal|Pos] -> 434 col_tangent_faces_1(Fs, D, Start+6, 435 add_col_uv_quad(Vs, Normal, Pos, UVs), 436 [{Face,{Start,6}}|FaceMap], 437 add_ts(Pos, [UV|| [_|UV] <- UVs], Normal, 438 wings_face:vertices_ccw(Face, We), Ts0)); 439 Info = {Normal,Faces,VsPos} -> 440 NoVs = length(Faces) * 3, 441 VsBin = add_col_uv_poly(Vs, Normal, Faces, 442 list_to_tuple(VsPos), list_to_tuple(UVs)), 443 col_tangent_faces_1(Fs, D, NoVs+Start, 444 VsBin, [{Face,{Start,NoVs}}|FaceMap], 445 add_ts(Info, [UV|| [_|UV] <- UVs], Normal, 446 wings_face:vertices_ccw(Face, We), Ts0)) 447 end; 448col_tangent_faces_1([], _, Start, Vs, FaceMap,Ts) -> 449 {Start,Vs,FaceMap,Ts}. 450 451 452setup_smooth_normals(D=#dlo{src_we=#we{}=We,ns=Ns0,mirror=MM, 453 vab=#vab{face_map=Fmap0}=Vab}) -> 454 Ns1 = array:sparse_foldl(fun(F,[N|_], A) -> [{F,N}|A]; 455 (F,{N,_,_}, A) -> [{F,N}|A] 456 end, [], Ns0), 457 Ns = reverse(Ns1), 458 Flist = wings_we:normals(Ns, We, MM), 459 Ftab = array:from_orddict(Flist), 460 Fs = lists:keysort(2, array:sparse_to_orddict(Fmap0)), 461 SN = setup_smooth_normals(Fs, Ftab, Ns0, <<>>), 462 [Vbo] = gl:genBuffers(1), 463 gl:bindBuffer(?GL_ARRAY_BUFFER, Vbo), 464 gl:bufferData(?GL_ARRAY_BUFFER, byte_size(SN), SN, ?GL_STATIC_DRAW), 465 gl:bindBuffer(?GL_ARRAY_BUFFER, 0), 466 D#dlo{vab=Vab#vab{face_sn={vbo,Vbo}}}. 467 468setup_smooth_normals([{Face,{_,3}}|Fs], Ftab, Flat, SN0) -> 469 %% One triangle. 470 case array:get(Face, Ftab) of 471 [N1,N2,N3] -> 472 %% Common case: the face is a triangle. 473 SN = add3(SN0, N1, N2, N3), 474 setup_smooth_normals(Fs, Ftab, Flat, SN); 475 _ -> 476 %% Degenerate case: The original face had more than 477 %% 3 vertices, so there should have been at least 478 %% 2 triangles, but some triangles were degenerated 479 %% and therefore discarded. Use the face normal 480 %% for all vertices. 481 {Fn,_,_} = array:get(Face, Flat), 482 SN = dup3(3, SN0, Fn), 483 setup_smooth_normals(Fs, Ftab, Flat, SN) 484 end; 485setup_smooth_normals([{Face,{_,6}}|Fs], Ftab, Flat, SN0) -> 486 %% Two triangles. 487 case array:get(Face, Ftab) of 488 [N1,N2,N3,N4] -> 489 %% Common case: triangulated quad. 490 SN = add4(SN0, N1, N2, N3, N4), 491 setup_smooth_normals(Fs, Ftab, Flat, SN); 492 _ -> 493 %% Degenerate case: The original face had more than 494 %% 4 vertices, so there should have been at least 495 %% 3 triangles, but some triangles were degenerated 496 %% and therefore discarded. Use the face normal 497 %% for all vertices. 498 {Fn,_,_} = array:get(Face, Flat), 499 SN = dup3(6, SN0, Fn), 500 setup_smooth_normals(Fs, Ftab, Flat, SN) 501 end; 502setup_smooth_normals([{Face,{_,Count}}|Fs], Ftab, Flat, SN0) -> 503 VsInfo = list_to_tuple(array:get(Face, Ftab)), 504 {FNormal,TriFs,Pos} = array:get(Face, Flat), 505 SN = case size(VsInfo) =:= length(Pos) of 506 true -> 507 setup_smooth_normals_1(TriFs,VsInfo,SN0); 508 false -> 509 %% Tesselated face set flat normals 510 %%(instead of random as previously) 511 dup3(Count,SN0,FNormal) 512 end, 513 setup_smooth_normals(Fs,Ftab,Flat,SN); 514setup_smooth_normals([],_,_,SN) -> SN. 515 516setup_smooth_normals_1([{A,B,C}|Fs], VsInfo, SN0) -> 517 N1 = element(A, VsInfo), 518 N2 = element(B, VsInfo), 519 N3 = element(C, VsInfo), 520 SN = add3(SN0, N1, N2, N3), 521 setup_smooth_normals_1(Fs,VsInfo,SN); 522setup_smooth_normals_1([], _, SN) -> SN. 523 524%% 525%% Create binaries 526%% 527 528add_tri(Bin, {NX,NY,NZ}, 529 [{X1,Y1,Z1},{X2,Y2,Z2},{X3,Y3,Z3}]) -> 530 <<Bin/binary, 531 X1:?F32,Y1:?F32,Z1:?F32, 532 NX:?F32,NY:?F32,NZ:?F32, 533 X2:?F32,Y2:?F32,Z2:?F32, 534 NX:?F32,NY:?F32,NZ:?F32, 535 X3:?F32,Y3:?F32,Z3:?F32, 536 NX:?F32,NY:?F32,NZ:?F32>>. 537 538add_tri(Bin, {NX,NY,NZ}, 539 [{X1,Y1,Z1},{X2,Y2,Z2},{X3,Y3,Z3}], 540 [{U1,V1},{U2,V2},{U3,V3}]) -> 541 <<Bin/binary, 542 X1:?F32,Y1:?F32,Z1:?F32, 543 NX:?F32,NY:?F32,NZ:?F32, 544 U1:?F32,V1:?F32, 545 X2:?F32,Y2:?F32,Z2:?F32, 546 NX:?F32,NY:?F32,NZ:?F32, 547 U2:?F32,V2:?F32, 548 X3:?F32,Y3:?F32,Z3:?F32, 549 NX:?F32,NY:?F32,NZ:?F32, 550 U3:?F32,V3:?F32>>; 551add_tri(Bin,N, Pos, _UV) -> 552 Z = {0.0,0.0}, 553 add_tri(Bin, N, Pos, [Z,Z,Z]). 554 555add_col_uv_tri(Bin, {NX,NY,NZ}, 556 [{X1,Y1,Z1},{X2,Y2,Z2},{X3,Y3,Z3}], 557 [[{R1,G1,B1}|{U1,V1}], 558 [{R2,G2,B2}|{U2,V2}], 559 [{R3,G3,B3}|{U3,V3}]]) -> 560 <<Bin/binary, 561 X1:?F32,Y1:?F32,Z1:?F32, 562 NX:?F32,NY:?F32,NZ:?F32, 563 R1:?F32,G1:?F32,B1:?F32, 564 U1:?F32,V1:?F32, 565 X2:?F32,Y2:?F32,Z2:?F32, 566 NX:?F32,NY:?F32,NZ:?F32, 567 R2:?F32,G2:?F32,B2:?F32, 568 U2:?F32,V2:?F32, 569 X3:?F32,Y3:?F32,Z3:?F32, 570 NX:?F32,NY:?F32,NZ:?F32, 571 R3:?F32,G3:?F32,B3:?F32, 572 U3:?F32,V3:?F32>>; 573add_col_uv_tri(Bin, N, Pos, Attrs0) -> 574 Attrs = fix_color_uv(Attrs0), 575 add_col_uv_tri(Bin, N, Pos, Attrs). 576 577add_col_tri(Bin, {NX,NY,NZ}, 578 [{X1,Y1,Z1},{X2,Y2,Z2},{X3,Y3,Z3}], 579 [{R1,G1,B1},{R2,G2,B2},{R3,G3,B3}]) -> 580 <<Bin/binary, 581 X1:?F32,Y1:?F32,Z1:?F32, 582 NX:?F32,NY:?F32,NZ:?F32, 583 R1:?F32,G1:?F32,B1:?F32, 584 X2:?F32,Y2:?F32,Z2:?F32, 585 NX:?F32,NY:?F32,NZ:?F32, 586 R2:?F32,G2:?F32,B2:?F32, 587 X3:?F32,Y3:?F32,Z3:?F32, 588 NX:?F32,NY:?F32,NZ:?F32, 589 R3:?F32,G3:?F32,B3:?F32>>; 590add_col_tri(Bin,N, Pos, Cols0) -> 591 Cols = [def_color(C) || C <- Cols0], 592 add_col_tri(Bin, N, Pos, Cols). 593 594add_quad(Bin, {NX,NY,NZ}, 595 [{X1,Y1,Z1},{X2,Y2,Z2},{X3,Y3,Z3},{X4,Y4,Z4}]) -> 596 <<Bin/binary, 597 X1:?F32,Y1:?F32,Z1:?F32, 598 NX:?F32,NY:?F32,NZ:?F32, 599 X2:?F32,Y2:?F32,Z2:?F32, 600 NX:?F32,NY:?F32,NZ:?F32, 601 X3:?F32,Y3:?F32,Z3:?F32, 602 NX:?F32,NY:?F32,NZ:?F32, 603 X3:?F32,Y3:?F32,Z3:?F32, 604 NX:?F32,NY:?F32,NZ:?F32, 605 X4:?F32,Y4:?F32,Z4:?F32, 606 NX:?F32,NY:?F32,NZ:?F32, 607 X1:?F32,Y1:?F32,Z1:?F32, 608 NX:?F32,NY:?F32,NZ:?F32>>. 609 610add_quad(Bin, {NX,NY,NZ}, 611 [{X1,Y1,Z1},{X2,Y2,Z2},{X3,Y3,Z3},{X4,Y4,Z4}], 612 [{U1,V1},{U2,V2},{U3,V3},{U4,V4}]) -> 613 <<Bin/binary, 614 X1:?F32,Y1:?F32,Z1:?F32, 615 NX:?F32,NY:?F32,NZ:?F32, 616 U1:?F32,V1:?F32, 617 X2:?F32,Y2:?F32,Z2:?F32, 618 NX:?F32,NY:?F32,NZ:?F32, 619 U2:?F32,V2:?F32, 620 X3:?F32,Y3:?F32,Z3:?F32, 621 NX:?F32,NY:?F32,NZ:?F32, 622 U3:?F32,V3:?F32, 623 X3:?F32,Y3:?F32,Z3:?F32, 624 NX:?F32,NY:?F32,NZ:?F32, 625 U3:?F32,V3:?F32, 626 X4:?F32,Y4:?F32,Z4:?F32, 627 NX:?F32,NY:?F32,NZ:?F32, 628 U4:?F32,V4:?F32, 629 X1:?F32,Y1:?F32,Z1:?F32, 630 NX:?F32,NY:?F32,NZ:?F32, 631 U1:?F32,V1:?F32>>; 632add_quad(Bin, N, Pos, _) -> 633 Z = {0.0,0.0}, 634 add_quad(Bin, N, Pos, [Z,Z,Z,Z]). 635 636add_col_quad(Bin, {NX,NY,NZ}, 637 [{X1,Y1,Z1},{X2,Y2,Z2},{X3,Y3,Z3},{X4,Y4,Z4}], 638 [{R1,G1,B1},{R2,G2,B2},{R3,G3,B3},{R4,G4,B4}]) -> 639 <<Bin/binary, 640 X1:?F32,Y1:?F32,Z1:?F32, 641 NX:?F32,NY:?F32,NZ:?F32, 642 R1:?F32,G1:?F32,B1:?F32, 643 X2:?F32,Y2:?F32,Z2:?F32, 644 NX:?F32,NY:?F32,NZ:?F32, 645 R2:?F32,G2:?F32,B2:?F32, 646 X3:?F32,Y3:?F32,Z3:?F32, 647 NX:?F32,NY:?F32,NZ:?F32, 648 R3:?F32,G3:?F32,B3:?F32, 649 X3:?F32,Y3:?F32,Z3:?F32, 650 NX:?F32,NY:?F32,NZ:?F32, 651 R3:?F32,G3:?F32,B3:?F32, 652 X4:?F32,Y4:?F32,Z4:?F32, 653 NX:?F32,NY:?F32,NZ:?F32, 654 R4:?F32,G4:?F32,B4:?F32, 655 X1:?F32,Y1:?F32,Z1:?F32, 656 NX:?F32,NY:?F32,NZ:?F32, 657 R1:?F32,G1:?F32,B1:?F32>>; 658add_col_quad(Bin, N, Pos, Cols0) -> 659 Cols = [def_color(C) || C <- Cols0], 660 add_col_quad(Bin, N, Pos, Cols). 661 662add_col_uv_quad(Bin, {NX,NY,NZ}, 663 [{X1,Y1,Z1},{X2,Y2,Z2},{X3,Y3,Z3},{X4,Y4,Z4}], 664 [[{R1,G1,B1}|{U1,V1}], 665 [{R2,G2,B2}|{U2,V2}], 666 [{R3,G3,B3}|{U3,V3}], 667 [{R4,G4,B4}|{U4,V4}]]) -> 668 <<Bin/binary, 669 X1:?F32,Y1:?F32,Z1:?F32, 670 NX:?F32,NY:?F32,NZ:?F32, 671 R1:?F32,G1:?F32,B1:?F32, 672 U1:?F32,V1:?F32, 673 X2:?F32,Y2:?F32,Z2:?F32, 674 NX:?F32,NY:?F32,NZ:?F32, 675 R2:?F32,G2:?F32,B2:?F32, 676 U2:?F32,V2:?F32, 677 X3:?F32,Y3:?F32,Z3:?F32, 678 NX:?F32,NY:?F32,NZ:?F32, 679 R3:?F32,G3:?F32,B3:?F32, 680 U3:?F32,V3:?F32, 681 X3:?F32,Y3:?F32,Z3:?F32, 682 NX:?F32,NY:?F32,NZ:?F32, 683 R3:?F32,G3:?F32,B3:?F32, 684 U3:?F32,V3:?F32, 685 X4:?F32,Y4:?F32,Z4:?F32, 686 NX:?F32,NY:?F32,NZ:?F32, 687 R4:?F32,G4:?F32,B4:?F32, 688 U4:?F32,V4:?F32, 689 X1:?F32,Y1:?F32,Z1:?F32, 690 NX:?F32,NY:?F32,NZ:?F32, 691 R1:?F32,G1:?F32,B1:?F32, 692 U1:?F32,V1:?F32>>; 693add_col_uv_quad(Bin, N, Pos, Attrs0) -> 694 Attrs = fix_color_uv(Attrs0), 695 add_col_uv_quad(Bin, N, Pos, Attrs). 696 697add_poly(Vs0, Normal, [{A,B,C}|Fs], Vtab) -> 698 PA = element(A, Vtab), 699 PB = element(B, Vtab), 700 PC = element(C, Vtab), 701 Vs = add_tri(Vs0, Normal, [PA,PB,PC]), 702 add_poly(Vs, Normal, Fs, Vtab); 703add_poly(Vs, _, _, _) -> Vs. 704 705add_poly(Vs0, Normal, [{A,B,C}|Fs], Vtab, UVtab) -> 706 PA = element(A, Vtab), 707 PB = element(B, Vtab), 708 PC = element(C, Vtab), 709 %% A tesselated face may have more Vs than UVs 710 UVa = uv_element(A, Vtab, UVtab), 711 UVb = uv_element(B, Vtab, UVtab), 712 UVc = uv_element(C, Vtab, UVtab), 713 Vs = add_tri(Vs0, Normal, [PA,PB,PC], [UVa,UVb,UVc]), 714 add_poly(Vs, Normal, Fs, Vtab, UVtab); 715add_poly(Vs, _, _, _, _) -> Vs. 716 717add_col_poly(Vs0, Normal, [{A,B,C}|Fs], Vtab, ColTab) -> 718 PA = element(A, Vtab), 719 PB = element(B, Vtab), 720 PC = element(C, Vtab), 721 %% A tesselated face may have more vertices than colors 722 ColA = col_element(A, Vtab, ColTab), 723 ColB = col_element(B, Vtab, ColTab), 724 ColC = col_element(C, Vtab, ColTab), 725 Vs = add_col_tri(Vs0, Normal, [PA,PB,PC], [ColA,ColB,ColC]), 726 add_col_poly(Vs, Normal, Fs, Vtab, ColTab); 727add_col_poly(Vs, _, _, _, _) -> Vs. 728 729add_col_uv_poly(Vs0, Normal, [{A,B,C}|Fs], Vtab, AttrTab) -> 730 PA = element(A, Vtab), 731 PB = element(B, Vtab), 732 PC = element(C, Vtab), 733 %% A tesselated face may have more vertices than vertex attributes 734 AttrA = attr_element(A, AttrTab), 735 AttrB = attr_element(B, AttrTab), 736 AttrC = attr_element(C, AttrTab), 737 Vs = add_col_uv_tri(Vs0, Normal, [PA,PB,PC], [AttrA,AttrB,AttrC]), 738 add_col_uv_poly(Vs, Normal, Fs, Vtab, AttrTab); 739add_col_uv_poly(Vs, _, _, _, _) -> Vs. 740 741uv_element(A, _Vtab, Tab) when A =< tuple_size(Tab) -> 742 element(A, Tab); 743uv_element(A, Vtab, Tab) -> 744 find_element(tuple_size(Tab), element(A, Vtab), Vtab, Tab, {0.0,0.0}). 745 746col_element(A, _, Tab) when A =< tuple_size(Tab) -> 747 element(A, Tab); 748col_element(A, Vtab, Tab) -> 749 find_element(tuple_size(Tab), element(A, Vtab), Vtab, Tab, {1.0,1.0,1.0}). 750 751find_element(0, _, _, _, Def) -> 752 Def; 753find_element(I, P, Vtab, UVTab, Def) -> 754 case P =:= element(I, Vtab) of 755 true -> element(I, UVTab); 756 false -> find_element(I-1, P, Vtab, UVTab, Def) 757 end. 758 759attr_element(A, Tab) when A =< tuple_size(Tab) -> 760 element(A, Tab); 761attr_element(_, _) -> 762 [none|none]. 763 764fix_color_uv(Attrs) -> 765 case good_uvs(Attrs) of 766 false -> 767 %% Bad UVs, possibly bad vertex colors too. Fix both. 768 Zuv = {0.0,0.0}, 769 [[def_color(C)|Zuv] || [C|_] <- Attrs]; 770 true -> 771 %% Good UVs, bad vertex colors. 772 [[def_color(C)|UV] || [C|UV] <- Attrs] 773 end. 774 775good_uvs([[_|{_,_}]|T]) -> good_uvs(T); 776good_uvs([_|_]) -> false; 777good_uvs([]) -> true. 778 779def_color({_,_,_}=C) -> C; 780def_color(_) -> {1.0,1.0,1.0}. 781 782add3(Bin, {X1,Y1,Z1}, {X2,Y2,Z2}, {X3,Y3,Z3}) -> 783 <<Bin/binary, 784 X1:?F32,Y1:?F32,Z1:?F32, 785 X2:?F32,Y2:?F32,Z2:?F32, 786 X3:?F32,Y3:?F32,Z3:?F32>>. 787 788add4(Bin, {X1,Y1,Z1}, {X2,Y2,Z2}, {X3,Y3,Z3}, {X4,Y4,Z4}) -> 789 <<Bin/binary, 790 X1:?F32,Y1:?F32,Z1:?F32, 791 X2:?F32,Y2:?F32,Z2:?F32, 792 X3:?F32,Y3:?F32,Z3:?F32, 793 X3:?F32,Y3:?F32,Z3:?F32, 794 X4:?F32,Y4:?F32,Z4:?F32, 795 X1:?F32,Y1:?F32,Z1:?F32>>. 796 797dup3(3, Bin, {NX,NY,NZ}) -> 798 <<Bin/binary, 799 NX:?F32,NY:?F32,NZ:?F32, 800 NX:?F32,NY:?F32,NZ:?F32, 801 NX:?F32,NY:?F32,NZ:?F32 >>; 802dup3(6, Bin, {NX,NY,NZ}) -> 803 <<Bin/binary, 804 NX:?F32,NY:?F32,NZ:?F32, 805 NX:?F32,NY:?F32,NZ:?F32, 806 NX:?F32,NY:?F32,NZ:?F32, 807 NX:?F32,NY:?F32,NZ:?F32, 808 NX:?F32,NY:?F32,NZ:?F32, 809 NX:?F32,NY:?F32,NZ:?F32 >>; 810dup3(0, Bin0, _N) -> %% Zero area triangulate face can become 0 vertex face 811 Bin0; 812dup3(I, Bin0, N={NX,NY,NZ}) when I > 0 -> 813 Bin = <<Bin0/binary, 814 NX:?F32,NY:?F32,NZ:?F32, 815 NX:?F32,NY:?F32,NZ:?F32, 816 NX:?F32,NY:?F32,NZ:?F32 >>, 817 dup3(I-3, Bin, N). 818 819add_ts([P1,P2,P3], [{U1,V1},{U2,V2},{U3,V3}], N, Vs, {Ts,F2V}) -> 820 {X1,Y1,Z1} = e3d_vec:sub(P2, P1), 821 {X2,Y2,Z2} = e3d_vec:sub(P3, P1), 822 S1 = U2-U1, 823 S2 = U3-U1, 824 T1 = V2-V1, 825 T2 = V3-V1, 826 try 827 F = 1.0 / (S1*T2 - S2*T1), 828 Tangent = {F*(T2*X1-T1*X2), F*(T2*Y1-T1*Y2), F*(T2*Z1-T1*Z2)}, 829 BiTangent = {F*(S1*X2-S2*X1), F*(S1*Y2-S2*Y1), F*(S1*Z2-S2*Z1)}, 830 H = case e3d_vec:dot(e3d_vec:cross(N, Tangent), BiTangent) < 0.0 of 831 true -> 1; 832 false -> -1 833 end, 834 {add_tangent(Vs, Tangent, BiTangent, Ts), [{N,H,Vs}|F2V]} 835 catch _:badarith -> 836 {Ts, [{N,0,Vs}|F2V]} 837 end; 838add_ts([P1,P2,P3,P4], [UV1,UV2,UV3,UV4], N, [V1,V2,V3,V4], Ts) -> % Quads 839 add_ts([P3,P4,P1],[UV3,UV4,UV1], N, [V3,V4,V1], 840 add_ts([P1,P2,P3],[UV1,UV2,UV3], N, [V1,V2,V3], Ts)); 841add_ts({_N,Fs,VsPos}, UVs, N, Vs, Ts) -> %% Polys 842 add_ts2(Fs, list_to_tuple(VsPos), list_to_tuple(UVs), N, list_to_tuple(Vs), Ts); 843add_ts([_,_,_], _, N, Vs, {Ts,F2V}) -> %% Bad UVs ignore 844 {Ts, [{N,1,Vs}|F2V]}. 845 846add_ts2([{V1,V2,V3}|Fs], VsPos, UVs, N, Vs, Ts0) -> 847 Ts = add_ts([element(V1,VsPos),element(V2,VsPos), element(V3,VsPos)], 848 [uv_element(V1, VsPos, UVs),uv_element(V2, VsPos, UVs),uv_element(V3, VsPos, UVs)], 849 N, 850 [id_element(V1, VsPos, Vs), id_element(V2, VsPos, Vs), id_element(V3, VsPos, Vs)], 851 Ts0), 852 add_ts2(Fs, VsPos, UVs, N, Vs, Ts); 853add_ts2([], _, _, _, _, Ts) -> Ts. 854 855id_element(A, _Vtab, Ids) when A =< tuple_size(Ids) -> element(A, Ids); 856id_element(A, Vtab, Ids) -> 857 find_element(tuple_size(Ids), element(A, Vtab), Vtab, Ids, element(1, Ids)). 858 859add_tangent([V|Vs], Tangent, BiTangent, Ts) -> 860 {T0, B0} = array:get(V,Ts), 861 add_tangent(Vs, Tangent, BiTangent, 862 array:set(V, {e3d_vec:add(T0, Tangent), e3d_vec:add(B0, BiTangent)}, Ts)); 863add_tangent([], _, _, Ts) -> Ts. 864 865add_tangents([{N, H, Face}|Fs], Ts, Bin0) -> 866 Bin = add_tangents1(Face, Ts, H, N, undefined, Bin0), 867 add_tangents(Fs, Ts, Bin); 868add_tangents([], _, Bin) -> Bin. 869 870add_tangents1([V|Vs], Ts, H0, N, Prev, Bin0) -> 871 case array:get(V, Ts) of 872 {{0.0, 0.0, 0.0}, BiT} -> 873 {Tan = {X,Y,Z}, H} = get_tangent(Prev, BiT, H0, N), 874 Bin = <<Bin0/binary, X:?F32,Y:?F32,Z:?F32, H:?F32>>, 875 add_tangents1(Vs, Ts, H, N, Tan, Bin); 876 {Tan = {X,Y,Z}, _} when H0 /= 0 -> 877 Bin = <<Bin0/binary, X:?F32,Y:?F32,Z:?F32, H0:?F32>>, 878 add_tangents1(Vs, Ts, H0, N, Tan, Bin); 879 {Tan = {X,Y,Z}, BiT} -> 880 H = case e3d_vec:dot(e3d_vec:cross(N, Tan), BiT) < 0.0 of 881 true -> 1; 882 false -> -1 883 end, 884 Bin = <<Bin0/binary, X:?F32,Y:?F32,Z:?F32, H:?F32>>, 885 add_tangents1(Vs, Ts, H, N, Tan, Bin) 886 end; 887add_tangents1([], _, _, _, _, Bin) -> Bin. 888 889get_tangent(undefined, {0.0,0.0,0.0}, H0, N) -> 890 H = if H0 =:= 0 -> -1; true -> H0 end, 891 {cross_axis(N), H}; 892get_tangent(undefined, BiT, 0, N) -> 893 T = e3d_vec:cross(BiT, N), 894 H = case e3d_vec:dot(e3d_vec:cross(N, T), BiT) < 0.0 of 895 true -> 1; 896 false -> -1 897 end, 898 {T, H}; 899get_tangent(undefined, BiT, H, N) -> 900 {e3d_vec:cross(BiT, N), H}; 901get_tangent(Prev, _, H, _) -> 902 {Prev, H}. 903 904cross_axis(N = {NX,NY,NZ}) -> 905 try 906 V2 = case abs(NX) > abs(NY) of 907 true -> 908 ILen = 1.0 / math:sqrt(NX*NX+NZ*NZ), 909 {-NZ*ILen, 0.0, NX * ILen}; 910 false -> 911 ILen = 1.0 / math:sqrt(NY*NY+NZ*NZ), 912 {0.0, NZ*ILen, -NY * ILen} 913 end, 914 e3d_vec:cross(N, V2) 915 catch _:badarith -> 916 {1.0, 0.0,0.0} 917 end. 918 919%%% 920%%% Collect information about faces. 921%%% 922 923-spec prepare([{_,_}], #dlo{}|#we{}, #st{}) -> plan(). 924 925prepare(Ftab, Dlo, St) -> 926 prepare(Ftab, Dlo, St, undefined). 927 928prepare(Ftab, #dlo{src_we=We}, St, Attr) -> 929 prepare(Ftab, We, St, Attr); 930prepare(Ftab0, #we{}=We, St, Attr) -> 931 Ftab = wings_we:visible(Ftab0, We), 932 prepare_1(Ftab, We, St, Attr). 933 934prepare_1(Ftab, We, St, Attr) -> 935 MatFaces = mat_faces(Ftab, We), 936 case wings_va:any_attributes(We) of 937 false when Attr =:= undefined -> 938 %% Since there are no vertex attributes, 939 %% we don't need to look at the materials 940 %% to figure out what to do. 941 {plain,MatFaces}; 942 false -> 943 {Attr, MatFaces}; 944 true -> 945 %% There are UV coordinates and/or vertex colors, 946 %% so we will have to look at the materials to 947 %% figure out what we'll need. 948 Attrs = wings_material:needed_attributes(We, St), 949 {prepare_2(Attr, Attrs),MatFaces} 950 end. 951 952prepare_2(Attr, _) 953 when Attr == plain; Attr == color; 954 Attr == uv; Attr == color_uv -> 955 Attr; 956prepare_2(_, []) -> 957 plain; 958prepare_2(_, Attrs) -> 959 prepare_3(Attrs, plain). 960 961prepare_3([color|Rest], Prev) -> 962 case wings_pref:get_value(show_colors) of 963 true -> prepare_3(Rest, color); 964 false -> prepare_3(Rest, Prev) 965 end; 966prepare_3([uv, tangent], Prev) -> 967 case wings_pref:get_value(show_normal_maps) of 968 true -> prepare_4(uv_tangent, Prev); 969 false -> prepare_3([uv], Prev) 970 end; 971prepare_3([uv], Prev) -> 972 case wings_pref:get_value(show_textures) of 973 true -> prepare_4(uv, Prev); 974 false -> Prev 975 end; 976prepare_3([], Attr) -> Attr. 977 978prepare_4(Attr, plain) -> Attr; 979prepare_4(uv, color) -> color_uv; 980prepare_4(uv_tangent, color) -> color_uv_tangent. 981 982 983mat_faces(Ftab, #we{id=Id}=We) when ?IS_AREA_LIGHT(We) -> 984 [{{'_area_light_',Id},Ftab}]; 985mat_faces(Ftab, We) -> 986 case wings_pref:get_value(show_materials) of 987 false -> 988 [{default,Ftab}]; 989 true -> 990 wings_facemat:mat_faces(Ftab, We) 991 end. 992 993%% create_tangent_vab(What, VsData, AllData, FaceMap, MatInfo) 994%% Create a #vab{} record with tangent data. 995 996create_tangent_vab(What, VsData, AllData, FaceMap, MatInfo) -> 997 Vab = create_vab(What, AllData, FaceMap, MatInfo), 998 VsSize = byte_size(VsData), 999 Vab#vab{data=VsData,face_ts={16,VsSize}}. 1000 1001%%% 1002%%% Create a #vab{} record. 1003%%% 1004 1005-type vab_item_tag() :: 1006 'vertices' | 1007 'face_normals' | 1008 'colors' | 1009 'uvs'. 1010 1011-spec create_vab([vab_item_tag()], binary(), any(), any()) -> #vab{}. 1012 1013create_vab(What, <<>>, FaceMap, MatInfo) -> 1014 [Vbo] = gl:genBuffers(1), 1015 gl:bindBuffer(?GL_ARRAY_BUFFER, Vbo), 1016 gl:bufferData(?GL_ARRAY_BUFFER, 0, <<>>, ?GL_STATIC_DRAW), 1017 gl:bindBuffer(?GL_ARRAY_BUFFER, 0), 1018 Empty = <<>>, 1019 Vab = #vab{id=Vbo,data=Empty,face_map=FaceMap,mat_map=MatInfo}, 1020 foldl(fun(E, Vab0) -> 1021 set_vab_item(E, {0,0}, Vab0) 1022 end, Vab, What); 1023create_vab(What, Data, FaceMap, MatInfo) -> 1024 Stride = lists:foldl(fun(Item, Sum) -> 1025 Sum + width(Item) 1026 end, 0, What), 1027 [Vbo] = gl:genBuffers(1), 1028 gl:bindBuffer(?GL_ARRAY_BUFFER, Vbo), 1029 gl:bufferData(?GL_ARRAY_BUFFER, byte_size(Data), Data, ?GL_STATIC_DRAW), 1030 gl:bindBuffer(?GL_ARRAY_BUFFER, 0), 1031 Vab = #vab{id=Vbo,data=Data,face_map=FaceMap,mat_map=MatInfo}, 1032 create_vab_1(What, 0, Stride, Data, Vab). 1033 1034create_vab_1([H|T], Pos, Stride, Data0, Vab0) -> 1035 Item = {Stride,Pos}, 1036 Vab = set_vab_item(H, Item, Vab0), 1037 create_vab_1(T, Pos+width(H), Stride, Data0, Vab); 1038create_vab_1([], _, _, _, Vab) -> Vab. 1039 1040set_vab_item(vertices, Item, Vab) -> 1041 Vab#vab{face_vs=Item}; 1042set_vab_item(face_normals, Item, Vab) -> 1043 Vab#vab{face_fn=Item}; 1044set_vab_item(colors, Item, Vab) -> 1045 Vab#vab{face_vc=Item}; 1046set_vab_item(uvs, Item, Vab) -> 1047 Vab#vab{face_uv=Item}. 1048 1049width(vertices) -> 3*4; 1050width(face_normals) -> 3*4; 1051width(vertex_normals) -> 3*4; 1052width(uvs) -> 2*4; 1053width(colors) -> 3*4. 1054