diff --git a/StartServerPy.bat b/StartServerPy.bat index 69a4f71..05f649c 100644 --- a/StartServerPy.bat +++ b/StartServerPy.bat @@ -1 +1 @@ -python -m http.server 8000 +python -m http.server 8080 diff --git a/package.json b/package.json index 5e6cd8e..fa2a452 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "online-3d-viewer", "description": "Online 3D Viewer", - "version": "0.7.14", + "version": "0.7.15", "repository": "github:kovacsv/Online3DViewer", "license": "MIT", "devDependencies": { diff --git a/sandbox/embed_selfhost_fullscreen.html b/sandbox/embed_selfhost_fullscreen.html index eeef69e..ead9190 100644 --- a/sandbox/embed_selfhost_fullscreen.html +++ b/sandbox/embed_selfhost_fullscreen.html @@ -27,6 +27,7 @@ + diff --git a/sandbox/embed_selfhost_multiple.html b/sandbox/embed_selfhost_multiple.html index 4f43e90..86c67bc 100644 --- a/sandbox/embed_selfhost_multiple.html +++ b/sandbox/embed_selfhost_multiple.html @@ -28,6 +28,7 @@ + diff --git a/sandbox/embed_selfhost_single.html b/sandbox/embed_selfhost_single.html index 99ef519..c8488a9 100644 --- a/sandbox/embed_selfhost_single.html +++ b/sandbox/embed_selfhost_single.html @@ -27,6 +27,7 @@ + diff --git a/sandbox/embed_selfhost_single_scroll.html b/sandbox/embed_selfhost_single_scroll.html index 25e28d9..ddd4511 100644 --- a/sandbox/embed_selfhost_single_scroll.html +++ b/sandbox/embed_selfhost_single_scroll.html @@ -27,6 +27,7 @@ + diff --git a/source/external/rhinoimporter.js b/source/external/rhinoimporter.js index 0b2ff74..0fd5c56 100644 --- a/source/external/rhinoimporter.js +++ b/source/external/rhinoimporter.js @@ -75,6 +75,7 @@ OV.Importer3dm = class extends OV.ImporterBase ImportRhinoDocument (rhinoDoc) { this.InitRhinoInstances (rhinoDoc); + this.ImportRhinoUserStrings (rhinoDoc); this.ImportRhinoGeometry (rhinoDoc); } @@ -95,6 +96,11 @@ OV.Importer3dm = class extends OV.ImporterBase } } + ImportRhinoUserStrings (rhinoDoc) + { + // TODO: https://github.com/mcneel/rhino3dm/issues/303 + } + ImportRhinoGeometry (rhinoDoc) { let rhinoObjects = rhinoDoc.objects (); @@ -113,7 +119,7 @@ OV.Importer3dm = class extends OV.ImporterBase if (rhinoAttributes.isInstanceDefinitionObject && rhinoInstanceReferences.length === 0) { return; } - + let rhinoMesh = null; let deleteMesh = false; @@ -174,6 +180,12 @@ OV.Importer3dm = class extends OV.ImporterBase let mesh = new OV.Mesh (); mesh.SetName (rhinoAttributes.name); + let userStrings = rhinoAttributes.getUserStrings (); + for (let i = 0; i < userStrings.length; i++) { + let userString = userStrings[i]; + mesh.AddProperty (new OV.Property (OV.PropertyType.Text, userString[0], userString[1])); + } + let materialIndex = this.GetMaterialIndex (rhinoDoc, rhinoObject, rhinoInstanceReferences); let threeJson = rhinoMesh.toThreejsJSON (); let vertices = threeJson.data.attributes.position.array; @@ -246,7 +258,7 @@ OV.Importer3dm = class extends OV.ImporterBase } } else if (rhinoAttributes.materialSource === rhino.ObjectMaterialSource.MaterialFromLayer) { let layerIndex = rhinoAttributes.layerIndex; - if (layerIndex > 0) { + if (layerIndex > -1) { let layer = rhinoDoc.layers ().get (layerIndex); let layerMaterialIndex = layer.renderMaterialIndex; if (layerMaterialIndex > -1) { diff --git a/source/import/importergltf.js b/source/import/importergltf.js index e2f6972..2f49956 100644 --- a/source/import/importergltf.js +++ b/source/import/importergltf.js @@ -476,6 +476,8 @@ OV.ImporterGltf = class extends OV.ImporterBase ProcessMainFile (gltf) { + this.ImportModelProperties (gltf); + let unsupportedExtensions = this.gltfExtensions.GetUnsupportedExtensions (gltf.extensionsRequired); if (unsupportedExtensions.length > 0) { this.SetError (); @@ -504,6 +506,18 @@ OV.ImporterGltf = class extends OV.ImporterBase } } + ImportModelProperties (gltf) + { + for (let propertyName in gltf.asset) { + if (gltf.asset.hasOwnProperty (propertyName)) { + if (typeof gltf.asset[propertyName] === 'string') { + const property = new OV.Property (OV.PropertyType.Text, propertyName, gltf.asset[propertyName]); + this.model.AddProperty (property); + } + } + } + } + GetDefaultScene (gltf) { let defaultSceneIndex = gltf.scene || 0; @@ -726,6 +740,8 @@ OV.ImporterGltf = class extends OV.ImporterBase this.model.AddMesh (mesh); if (gltfMesh.name !== undefined) { mesh.SetName (gltfMesh.name); + } else if (gltfNode.name !== undefined) { + mesh.SetName (gltfNode.name); } for (let i = 0; i < gltfMesh.primitives.length; i++) { diff --git a/source/model/element.js b/source/model/element.js index 238a257..639769f 100644 --- a/source/model/element.js +++ b/source/model/element.js @@ -3,6 +3,7 @@ OV.Element = class constructor () { this.name = ''; + this.properties = []; } GetName () @@ -35,6 +36,22 @@ OV.Element = class return 0; } + PropertyCount () + { + return this.properties.length; + } + + AddProperty (property) + { + this.properties.push (property); + return this.properties.length - 1; + } + + GetProperty (index) + { + return this.properties[index]; + } + EnumerateVertices (onVertex) { diff --git a/source/model/modelutils.js b/source/model/modelutils.js index c321a9b..c077589 100644 --- a/source/model/modelutils.js +++ b/source/model/modelutils.js @@ -2,13 +2,7 @@ OV.CalculateTriangleNormal = function (v0, v1, v2) { let v = OV.SubCoord3D (v1, v0); let w = OV.SubCoord3D (v2, v0); - - let normal = new OV.Coord3D ( - v.y * w.z - v.z * w.y, - v.z * w.x - v.x * w.z, - v.x * w.y - v.y * w.x - ); - + let normal = OV.CrossVector3D (v, w); normal.Normalize (); return normal; }; diff --git a/source/model/property.js b/source/model/property.js new file mode 100644 index 0000000..f99d72e --- /dev/null +++ b/source/model/property.js @@ -0,0 +1,18 @@ +OV.PropertyType = +{ + Text : 1, + Integer : 2, + Number : 3, + Percent : 4, + Color : 5 +}; + +OV.Property = class +{ + constructor (type, name, value) + { + this.type = type; + this.name = name; + this.value = value; + } +}; diff --git a/test/tests/model_test.js b/test/tests/model_test.js index 6189302..1c92a18 100644 --- a/test/tests/model_test.js +++ b/test/tests/model_test.js @@ -184,6 +184,20 @@ describe ('Model Finalization', function() { }); }); +describe ('Model Properties', function() { + let model = new OV.Model (); + model.AddProperty (new OV.Property (OV.PropertyType.Text, 'name 01', 'value 01')); + model.AddProperty (new OV.Property (OV.PropertyType.Integer, 'name 02', 2)); + model.AddProperty (new OV.Property (OV.PropertyType.Number, 'name 03', 3.5)); + assert.strictEqual (model.PropertyCount (), 3); + assert.strictEqual (model.GetProperty (0).name, 'name 01'); + assert.strictEqual (model.GetProperty (0).value, 'value 01'); + assert.strictEqual (model.GetProperty (1).name, 'name 02'); + assert.strictEqual (model.GetProperty (1).value, 2); + assert.strictEqual (model.GetProperty (2).name, 'name 03'); + assert.strictEqual (model.GetProperty (2).value, 3.5); +}); + describe ('Color Conversion', function() { it ('Color equality check', function () { assert (OV.ColorIsEqual (new OV.Color (10, 20, 30), new OV.Color (10, 20, 30))); diff --git a/tools/config.json b/tools/config.json index 51bebd3..2ff3718 100644 --- a/tools/config.json +++ b/tools/config.json @@ -22,6 +22,7 @@ "source/io/fileutils.js", "source/model/material.js", "source/model/triangle.js", + "source/model/property.js", "source/model/element.js", "source/model/mesh.js", "source/model/meshbuffer.js", @@ -64,6 +65,7 @@ "website_files" : [ "website/o3dv/featureset.js", "website/o3dv/utils.js", + "website/o3dv/cookies.js", "website/o3dv/toolbar.js", "website/o3dv/treeview.js", "website/o3dv/modal.js", @@ -72,10 +74,10 @@ "website/o3dv/exportdialog.js", "website/o3dv/sharingdialog.js", "website/o3dv/settingsdialog.js", - "website/o3dv/quantitiesdialog.js", + "website/o3dv/cookiedialog.js", "website/o3dv/modeldata.js", - "website/o3dv/info.js", "website/o3dv/navigator.js", + "website/o3dv/sidebar.js", "website/o3dv/hashhandler.js", "website/o3dv/website.css", "website/o3dv/loader.js", diff --git a/website/assets/images/3dviewer_net_logo_social.svg b/website/assets/images/3dviewer_net_logo_social.svg index 394c7c3..e6433b3 100644 --- a/website/assets/images/3dviewer_net_logo_social.svg +++ b/website/assets/images/3dviewer_net_logo_social.svg @@ -1,256 +1 @@ - -image/svg+xml \ No newline at end of file + \ No newline at end of file diff --git a/website/assets/images/3dviewer_net_start_page.png b/website/assets/images/3dviewer_net_start_page.png index f062512..973e0c3 100644 Binary files a/website/assets/images/3dviewer_net_start_page.png and b/website/assets/images/3dviewer_net_start_page.png differ diff --git a/website/assets/images/header/github.svg b/website/assets/images/header/github.svg index b7779c8..0085e51 100644 --- a/website/assets/images/header/github.svg +++ b/website/assets/images/header/github.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/website/assets/images/header/github_hover.svg b/website/assets/images/header/github_hover.svg index 1a7ddc8..8b93c2e 100644 --- a/website/assets/images/header/github_hover.svg +++ b/website/assets/images/header/github_hover.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/website/assets/images/sidebar/close.svg b/website/assets/images/sidebar/close.svg new file mode 100644 index 0000000..abc131e --- /dev/null +++ b/website/assets/images/sidebar/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/assets/images/tree/details.svg b/website/assets/images/toolbar/details.svg similarity index 100% rename from website/assets/images/tree/details.svg rename to website/assets/images/toolbar/details.svg diff --git a/website/assets/images/toolbar/details_blue.svg b/website/assets/images/toolbar/details_blue.svg new file mode 100644 index 0000000..4b76fbf --- /dev/null +++ b/website/assets/images/toolbar/details_blue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/embed.html b/website/embed.html index 8d08058..f265780 100644 --- a/website/embed.html +++ b/website/embed.html @@ -35,6 +35,7 @@ + @@ -78,6 +79,7 @@ + @@ -86,10 +88,10 @@ - + - + diff --git a/website/examples.html b/website/examples.html index c1361e2..b71285c 100644 --- a/website/examples.html +++ b/website/examples.html @@ -16,6 +16,7 @@
  • hundred_cubes.obj
  • icosahedron.obj
  • error.obj
  • +
  • Box.glb
  • diff --git a/website/index.html b/website/index.html index 67e6034..579c67d 100644 --- a/website/index.html +++ b/website/index.html @@ -35,6 +35,7 @@ + @@ -78,6 +79,7 @@ + @@ -86,10 +88,10 @@ - + - + @@ -111,6 +113,7 @@ mainDiv : $('#main'), introDiv : $('#intro'), navigatorDiv : $('#main_navigator'), + sidebarDiv : $('#main_sidebar'), viewerDiv : $('#main_viewer'), fileInput : $('#open_file') }); @@ -144,6 +147,8 @@
    +
    +
    diff --git a/website/o3dv/cookiedialog.js b/website/o3dv/cookiedialog.js new file mode 100644 index 0000000..0e3db04 --- /dev/null +++ b/website/o3dv/cookiedialog.js @@ -0,0 +1,19 @@ +OV.ShowCookieDialog = function (onAccept) +{ + let dialog = new OV.ButtonDialog (); + let contentDiv = dialog.Init ('Cookie Consent', [ + { + name : 'Accept', + onClick () { + dialog.Hide (); + onAccept (); + } + } + ]); + + let text = 'This website uses cookies to offer you better user experience. See the details at the Cookies Policy page.'; + $('
    ').html (text).addClass ('ov_dialog_section').appendTo (contentDiv); + dialog.SetCloseable (false); + dialog.Show (); + return dialog; +}; diff --git a/website/o3dv/cookies.js b/website/o3dv/cookies.js new file mode 100644 index 0000000..ee8dc3a --- /dev/null +++ b/website/o3dv/cookies.js @@ -0,0 +1,46 @@ +OV.CookieHandler = class +{ + constructor () + { + this.expirationDays = 365; + } + + ClearVal (key) + { + this.SetStringVal (key, ''); + } + + GetBoolVal (key, defVal) + { + let stringVal = this.GetStringVal (key); + if (stringVal === null) { + return defVal; + } + return stringVal === 'true' ? true : false; + } + + SetBoolVal (key, value) + { + this.SetStringVal (key, value ? 'true' : false); + } + + SetStringVal (key, value) + { + let date = new Date (); + date.setTime (date.getTime () + (this.expirationDays * 24 * 60 * 60 * 1000)); + document.cookie = key + '=' + value + '; expires=' + date.toUTCString () + ';'; + } + + GetStringVal (key) + { + let cookie = decodeURIComponent (document.cookie); + let cookieParts = cookie.split (';'); + for (let i = 0; i < cookieParts.length; i++) { + let currentCookie = cookieParts[i].trim (); + if (currentCookie.startsWith (key + '=')) { + return currentCookie.substr (key.length + 1); + } + } + return null; + } +}; diff --git a/website/o3dv/featureset.js b/website/o3dv/featureset.js index aa2364e..e06b5ce 100644 --- a/website/o3dv/featureset.js +++ b/website/o3dv/featureset.js @@ -1,5 +1,4 @@ OV.FeatureSet = { - SetDefaultColor : false, - CalculateQuantities : false + SetDefaultColor : false }; diff --git a/website/o3dv/info.js b/website/o3dv/info.js deleted file mode 100644 index 2e59dbe..0000000 --- a/website/o3dv/info.js +++ /dev/null @@ -1,173 +0,0 @@ -OV.InfoPanel = class -{ - constructor (parentDiv) - { - this.mainDiv = $('
    ').addClass ('ov_info_panel_main').appendTo (parentDiv); - this.treeView = new OV.TreeView (this.mainDiv); - this.detailsItem = new OV.TreeViewGroupItem ('Details', 'assets/images/tree/details.svg'); - this.detailsItem.ShowChildren (!OV.IsSmallHeight (), null); - this.treeView.AddItem (this.detailsItem); - let childrenDiv = this.detailsItem.CreateChildrenDiv (); - childrenDiv.addClass ('ov_info_panel_content'); - this.popup = null; - } - - SetOpenCloseHandler (openCloseHandler) - { - this.detailsItem.SetAnimated (false); - this.detailsItem.SetOpenCloseHandler (openCloseHandler); - } - - FillWithMaterialInfo (info, callbacks) - { - function AddRow (container, name, fillValue) - { - let row = $('
    ').addClass ('ov_info_box_row').appendTo (container); - $('
    ').addClass ('ov_info_box_row_name').html (name).appendTo (row); - let value = $('
    ').addClass ('ov_info_box_row_value').appendTo (row); - fillValue (value); - } - - function AddTextRow (container, name, value) - { - AddRow (container, name, function (valueDiv) { - valueDiv.html (value).attr ('title', value); - }); - } - - function AddTextureRow (container, textureName) - { - AddRow (container, textureName.type, function (valueDiv) { - valueDiv.html (textureName.name).attr ('title', textureName.path); - }); - } - - this.Clear (); - if (info === null) { - return; - } - - let contentDiv = this.detailsItem.GetChildrenDiv (); - - let infoContainer = $('
    ').addClass ('ov_info_box').appendTo (contentDiv); - AddRow (infoContainer, 'Color', function (valueDiv) { - let colorString = '#' + OV.ColorToHexString (info.diffuse); - $('
    ').addClass ('ov_info_box_rgbbox').css ('background', colorString).attr ('title', colorString).appendTo (valueDiv); - $('
    ').addClass ('ov_info_box_rgbtext').html (colorString).attr ('title', colorString).appendTo (valueDiv); - }); - let opacityString = parseInt (Math.round (info.opacity * 100.0), 10) + '%'; - AddTextRow (infoContainer, 'Opacity', opacityString); - - if (info.textureNames.length > 0) { - let texturesContainer = $('
    ').addClass ('ov_info_box').appendTo (contentDiv); - $('
    ').addClass ('ov_info_box_title').html ('Textures').appendTo (texturesContainer); - let texturesContent = $('
    ').addClass ('ov_info_box_details').appendTo (texturesContainer); - for (let i = 0; i < info.textureNames.length; i++) { - let textureName = info.textureNames[i]; - AddTextureRow (texturesContent, textureName); - } - } - - let meshItems = []; - for (let i = 0; i < info.usedByMeshes.length; i++) { - let meshInfo = info.usedByMeshes[i]; - meshItems.push ({ - name : OV.GetMeshName (meshInfo.name) - }); - } - - let obj = this; - let meshesText = 'Meshes (' + meshItems.length + ')'; - this.CreateButton (contentDiv, meshesText, function (button) { - if (meshItems.length === 0) { - return; - } - obj.popup = OV.ShowListPopup (button, meshItems, { - onHoverStart : function (index) { - const meshItem = info.usedByMeshes[index]; - callbacks.onMeshHover (meshItem.index); - }, - onHoverStop : function (index) { - callbacks.onMeshHover (null); - }, - onClick : function (index) { - const meshItem = info.usedByMeshes[index]; - callbacks.onMeshSelect (meshItem.index); - } - }); - }); - } - - FillWithModelInfo (info, callbacks) - { - function AddCounter (parent, name, value) - { - let infoBox = $('
    ').addClass ('ov_info_box_column').css ('width', '50%').appendTo (parent); - $('
    ').addClass ('ov_info_box_title').html (name).appendTo (infoBox); - $('
    ').addClass ('ov_info_box_content_big').html (value.toLocaleString ('en-US')).appendTo (infoBox); - } - - this.Clear (); - if (info === null) { - return; - } - - let contentDiv = this.detailsItem.GetChildrenDiv (); - - let counterContainer = $('
    ').addClass ('ov_info_box').appendTo (contentDiv); - AddCounter (counterContainer, 'Vertices', info.element.VertexCount ()); - AddCounter (counterContainer, 'Triangles', info.element.TriangleCount ()); - - let sizeContainer = $('
    ').addClass ('ov_info_box').appendTo (contentDiv); - $('
    ').addClass ('ov_info_box_title').html ('Size').appendTo (sizeContainer); - let size = OV.SubCoord3D (info.boundingBox.max, info.boundingBox.min); - let sizeString = size.x.toFixed (1) + ' x ' + size.y.toFixed (1) + ' x ' + size.z.toFixed (1); - $('
    ').addClass ('ov_info_box_content').html (sizeString).attr ('title', sizeString).appendTo (sizeContainer); - - let materialItems = []; - for (let i = 0; i < info.usedMaterials.length; i++) { - let usedMaterial = info.usedMaterials[i]; - materialItems.push ({ - name : OV.GetMaterialName (usedMaterial.name), - color : OV.ColorToHexString (usedMaterial.diffuse) - }); - } - - let obj = this; - if (OV.FeatureSet.CalculateQuantities) { - this.CreateButton (contentDiv, 'Calculate Quantities', function (button) { - obj.popup = OV.ShowQuantitiesPopup (button, info.element); - }); - } - - let materialsText = 'Materials (' + materialItems.length + ')'; - this.CreateButton (contentDiv, materialsText, function (button) { - obj.popup = OV.ShowListPopup (button, materialItems, { - onClick : function (index) { - let usedMaterial = info.usedMaterials[index]; - callbacks.onMaterialSelect (usedMaterial.index); - } - }); - }); - } - - CreateButton (parentDiv, buttonText, onClick) - { - let button = $('
    ').addClass ('ov_info_box_button').appendTo (parentDiv); - $('
    ').addClass ('ov_info_box_button_text').html (buttonText).appendTo (button); - $('').addClass ('ov_info_box_button_icon').attr ('src', 'assets/images/tree/arrow_right.svg').appendTo (button); - button.click (function () { - onClick (button); - }); - } - - Clear () - { - if (this.popup !== null) { - this.popup.Hide (); - this.popup = null; - } - let contentDiv = this.detailsItem.GetChildrenDiv (); - contentDiv.empty (); - } -}; diff --git a/website/o3dv/modal.js b/website/o3dv/modal.js index 57e565d..be787dc 100644 --- a/website/o3dv/modal.js +++ b/website/o3dv/modal.js @@ -165,6 +165,11 @@ OV.ButtonDialog = class return dialogContentDiv; } + SetCloseable (closeable) + { + this.modal.SetCloseable (closeable); + } + SetCloseHandler (closeHandler) { this.modal.SetCloseHandler (closeHandler); @@ -239,7 +244,9 @@ OV.ListPopup = class extends OV.PopupDialog { let listItemDiv = $('
    ').addClass ('ov_popup_list_item').appendTo (this.listDiv); if (item.color) { - $('
    ').addClass ('ov_popup_list_item_rgbbox').css ('background', '#' + item.color).appendTo (listItemDiv); + let iconDiv = $('
    ').addClass ('ov_popup_list_item_icon').appendTo (listItemDiv); + let colorCircle = OV.CreateInlineColorCircle (item.color); + colorCircle.appendTo (iconDiv); } $('
    ').addClass ('ov_popup_list_item_name').html (item.name).appendTo (listItemDiv); listItemDiv.click (callbacks.onClick); diff --git a/website/o3dv/navigator.js b/website/o3dv/navigator.js index c71ec9b..bda2ada 100644 --- a/website/o3dv/navigator.js +++ b/website/o3dv/navigator.js @@ -13,17 +13,111 @@ OV.Selection = class } }; -OV.Navigator = class +OV.NavigatorInfoPanel = class { constructor (parentDiv) { this.parentDiv = parentDiv; + this.popup = null; + } + + FillWithMaterialInfo (usedByMeshes, callbacks) + { + this.Clear (); + if (usedByMeshes === null) { + return; + } + + let meshItems = []; + for (let i = 0; i < usedByMeshes.length; i++) { + let meshInfo = usedByMeshes[i]; + meshItems.push ({ + name : OV.GetMeshName (meshInfo.name) + }); + } + + let obj = this; + let meshesText = 'Meshes (' + meshItems.length + ')'; + this.CreateButton (this.parentDiv, meshesText, function (button) { + if (meshItems.length === 0) { + return; + } + obj.popup = OV.ShowListPopup (button, meshItems, { + onHoverStart : function (index) { + const meshItem = usedByMeshes[index]; + callbacks.onMeshHover (meshItem.index); + }, + onHoverStop : function (index) { + callbacks.onMeshHover (null); + }, + onClick : function (index) { + const meshItem = usedByMeshes[index]; + callbacks.onMeshSelect (meshItem.index); + } + }); + }); + } + + FillWithModelInfo (usedMaterials, callbacks) + { + this.Clear (); + if (usedMaterials === null) { + return; + } + + let materialItems = []; + for (let i = 0; i < usedMaterials.length; i++) { + let usedMaterial = usedMaterials[i]; + materialItems.push ({ + name : OV.GetMaterialName (usedMaterial.name), + color : usedMaterial.diffuse + }); + } + + let obj = this; + let materialsText = 'Materials (' + materialItems.length + ')'; + this.CreateButton (this.parentDiv, materialsText, function (button) { + obj.popup = OV.ShowListPopup (button, materialItems, { + onClick : function (index) { + let usedMaterial = usedMaterials[index]; + callbacks.onMaterialSelect (usedMaterial.index); + } + }); + }); + } + + CreateButton (parentDiv, buttonText, onClick) + { + let button = $('
    ').addClass ('ov_navigator_info_button').appendTo (parentDiv); + $('
    ').addClass ('ov_navigator_info_button_text').html (buttonText).appendTo (button); + $('').addClass ('ov_navigator_info_button_icon').attr ('src', 'assets/images/tree/arrow_right.svg').appendTo (button); + button.click (function () { + onClick (button); + }); + } + + Clear () + { + if (this.popup !== null) { + this.popup.Hide (); + this.popup = null; + } + this.parentDiv.empty (); + } +}; + +OV.Navigator = class +{ + constructor (parentDiv, sidebar) + { + this.parentDiv = parentDiv; + this.sidebar = sidebar; this.callbacks = null; - this.titleDiv = $('
    ').addClass ('ov_navigator_tree_title').addClass ('ov_thin_scrollbar').appendTo (parentDiv); + this.titleDiv = $('
    ').addClass ('ov_navigator_tree_title').appendTo (parentDiv); this.treeDiv = $('
    ').addClass ('ov_navigator_tree_panel').addClass ('ov_thin_scrollbar').appendTo (parentDiv); this.infoDiv = $('
    ').addClass ('ov_navigator_info_panel').addClass ('ov_thin_scrollbar').appendTo (parentDiv); this.treeView = new OV.TreeView (this.treeDiv); - this.infoPanel = new OV.InfoPanel (this.infoDiv); + this.infoPanel = new OV.NavigatorInfoPanel (this.infoDiv); this.modelData = new OV.ModelData (); this.selection = null; this.tempSelectedMeshIndex = null; @@ -31,11 +125,7 @@ OV.Navigator = class Init (callbacks) { - let obj = this; this.callbacks = callbacks; - this.infoPanel.SetOpenCloseHandler (function () { - obj.Resize (); - }); } Resize () @@ -220,16 +310,18 @@ OV.Navigator = class { let obj = this; if (this.selection === null) { - let modelInfo = this.callbacks.getModelInformation (); - this.infoPanel.FillWithModelInfo (modelInfo, { + let usedMaterials = this.callbacks.getMaterialsForModel (); + this.infoPanel.FillWithModelInfo (usedMaterials, { onMaterialSelect : function (materialIndex) { obj.SetSelection (new OV.Selection (OV.SelectionType.Material, materialIndex)); } }); + let model = this.callbacks.getModel (); + this.sidebar.AddElementProperties (model); } else { if (this.selection.type === OV.SelectionType.Material) { - let materialInfo = this.callbacks.getMaterialInformation (this.selection.index); - this.infoPanel.FillWithMaterialInfo (materialInfo, { + let usedByMeshes = this.callbacks.getMeshesForMaterial (this.selection.index); + this.infoPanel.FillWithMaterialInfo (usedByMeshes, { onMeshHover : function (meshIndex) { obj.SetTempSelectedMeshIndex (meshIndex); }, @@ -237,13 +329,19 @@ OV.Navigator = class obj.SetSelection (new OV.Selection (OV.SelectionType.Mesh, meshIndex)); } }); + let model = this.callbacks.getModel (); + let material = model.GetMaterial (this.selection.index); + this.sidebar.AddMaterialProperties (material); } else if (this.selection.type === OV.SelectionType.Mesh) { - let meshInfo = this.callbacks.getMeshInformation (this.selection.index); - this.infoPanel.FillWithModelInfo (meshInfo, { + let usedMaterials = this.callbacks.getMaterialsForMesh (this.selection.index); + this.infoPanel.FillWithModelInfo (usedMaterials, { onMaterialSelect : function (materialIndex) { obj.SetSelection (new OV.Selection (OV.SelectionType.Material, materialIndex)); } }); + let model = this.callbacks.getModel (); + let mesh = model.GetMesh (this.selection.index); + this.sidebar.AddElementProperties (mesh); } } this.Resize (); diff --git a/website/o3dv/quantitiesdialog.js b/website/o3dv/quantitiesdialog.js deleted file mode 100644 index a0d0552..0000000 --- a/website/o3dv/quantitiesdialog.js +++ /dev/null @@ -1,29 +0,0 @@ -OV.ShowQuantitiesPopup = function (parentItem, element) -{ - let popup = new OV.PopupDialog (); - let contentDiv = popup.Init (parentItem); - - $('
    ').addClass ('ov_popup_title').html ('Volume').appendTo (contentDiv); - let volumeDiv = $('
    ').addClass ('ov_popup_text').html ('Calculating...').appendTo (contentDiv); - $('
    ').addClass ('ov_popup_title').html ('Surface Area').appendTo (contentDiv); - let surfaceAreaDiv = $('
    ').addClass ('ov_popup_text').html ('Calculating...').appendTo (contentDiv); - - OV.RunTaskAsync (function () { - const volume = OV.CalculateVolume (element); - const surfaceArea = OV.CalculateSurfaceArea (element); - - let volumeString = ''; - if (volume === null) { - volumeString = 'The model is not closed.'; - } else { - volumeString = volume.toFixed (5); - } - let surfaceAreaString = surfaceArea.toFixed (5); - - volumeDiv.html (volumeString); - surfaceAreaDiv.html (surfaceAreaString); - }); - - popup.Show (); - return popup; -}; diff --git a/website/o3dv/sidebar.js b/website/o3dv/sidebar.js new file mode 100644 index 0000000..c19cd17 --- /dev/null +++ b/website/o3dv/sidebar.js @@ -0,0 +1,168 @@ +OV.Sidebar = class +{ + constructor (parentDiv) + { + this.parentDiv = parentDiv; + this.callbacks = null; + this.visible = true; + this.titleDiv = null; + this.contentDiv = null; + + } + + Init (callbacks) + { + this.callbacks = callbacks; + this.titleDiv = $('
    ').addClass ('ov_sidebar_title').appendTo (this.parentDiv); + this.contentDiv = $('
    ').addClass ('ov_sidebar_content').addClass ('ov_thin_scrollbar').appendTo (this.parentDiv); + let titleTextDiv = $('
    ').addClass ('ov_sidebar_title_text').html ('Details').appendTo (this.titleDiv); + let titleImg = $('').addClass ('ov_sidebar_title_img').attr ('src', 'assets/images/sidebar/close.svg').appendTo (this.titleDiv); + let obj = this; + titleImg.click (function () { + obj.callbacks.onClose (); + }); + } + + Show (show) + { + this.visible = show; + if (this.visible) { + this.parentDiv.show (); + } else { + this.parentDiv.hide (); + } + } + + IsVisible () + { + return this.visible; + } + + AddProperty (table, property) + { + let row = $('
    ').addClass ('ov_property_table_row').appendTo (table); + let nameColum = $('
    ').addClass ('ov_property_table_cell ov_property_table_name').appendTo (row); + let valueColumn = $('
    ').addClass ('ov_property_table_cell ov_property_table_value').appendTo (row); + nameColum.html (property.name + ':').attr ('title', property.name); + this.DisplayPropertyValue (property, valueColumn); + } + + AddCalculatedProperty (table, name, calculateValue) + { + let row = $('
    ').addClass ('ov_property_table_row').appendTo (table); + let nameColum = $('
    ').addClass ('ov_property_table_cell ov_property_table_name').appendTo (row); + let valueColumn = $('
    ').addClass ('ov_property_table_cell ov_property_table_value').appendTo (row); + nameColum.html (name + ':').attr ('title', name); + + let obj = this; + let calculateButton = $('
    ').addClass ('ov_property_table_button').html ('Calculate...').appendTo (valueColumn); + calculateButton.click (function () { + valueColumn.empty (); + valueColumn.html ('Please wait...'); + OV.RunTaskAsync (function () { + let propertyValue = calculateValue (); + if (propertyValue === null) { + valueColumn.html ('-'); + } else { + obj.DisplayPropertyValue (propertyValue, valueColumn); + } + }); + }); + } + + DisplayPropertyValue (property, targetDiv) + { + targetDiv.empty (); + let valueText = null; + if (property.type === OV.PropertyType.Text) { + valueText = property.value; + } else if (property.type === OV.PropertyType.Integer) { + valueText = property.value.toLocaleString (); + } else if (property.type === OV.PropertyType.Number) { + valueText = property.value.toLocaleString (undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }); + } else if (property.type === OV.PropertyType.Percent) { + valueText = parseInt (property.value * 100, 10).toString () + '%'; + } else if (property.type === OV.PropertyType.Color) { + let hexString = '#' + OV.ColorToHexString (property.value); + let colorCircle = OV.CreateInlineColorCircle (property.value); + colorCircle.appendTo (targetDiv); + $('').html (hexString).appendTo (targetDiv); + } + if (valueText !== null) { + targetDiv.html (valueText).attr ('title', valueText); + } + } + + AddElementProperties (element) + { + this.Clear (); + let table = $('
    ').addClass ('ov_property_table').appendTo (this.contentDiv); + let boundingBox = OV.GetBoundingBox (element); + let size = OV.SubCoord3D (boundingBox.max, boundingBox.min); + this.AddProperty (table, new OV.Property (OV.PropertyType.Integer, 'Vertex Count', element.VertexCount ())); + this.AddProperty (table, new OV.Property (OV.PropertyType.Integer, 'Triangle Count', element.TriangleCount ())); + this.AddProperty (table, new OV.Property (OV.PropertyType.Number, 'Size X', size.x)); + this.AddProperty (table, new OV.Property (OV.PropertyType.Number, 'Size Y', size.y)); + this.AddProperty (table, new OV.Property (OV.PropertyType.Number, 'Size Z', size.z)); + this.AddCalculatedProperty (table, 'Volume', function () { + const volume = OV.CalculateVolume (element); + if (volume === null) { + return null; + } + return new OV.Property (OV.PropertyType.Number, null, volume); + }); + this.AddCalculatedProperty (table, 'Surface Area', function () { + const volume = OV.CalculateSurfaceArea (element); + if (volume === null) { + return null; + } + return new OV.Property (OV.PropertyType.Number, null, volume); + }); + if (element.PropertyCount () > 0) { + let customTable = $('
    ').addClass ('ov_property_table ov_property_table_custom').appendTo (this.contentDiv); + for (let i = 0; i < element.PropertyCount (); i++) { + const property = element.GetProperty (i); + this.AddProperty (customTable, property); + } + } + this.Resize (); + } + + AddMaterialProperties (material) + { + function AddTextureMap (obj, table, name, map) + { + if (map === null || map.name === null) { + return; + } + let fileName = OV.GetFileName (map.name); + obj.AddProperty (table, new OV.Property (OV.PropertyType.Text, name, fileName)); + } + + this.Clear (); + let table = $('
    ').addClass ('ov_property_table').appendTo (this.contentDiv); + this.AddProperty (table, new OV.Property (OV.PropertyType.Color, 'Color', material.diffuse)); + this.AddProperty (table, new OV.Property (OV.PropertyType.Percent, 'Opacity', material.opacity)); + AddTextureMap (this, table, 'Diffuse Map', material.diffuseMap); + AddTextureMap (this, table, 'Specular Map', material.specularMap); + AddTextureMap (this, table, 'Bump Map', material.bumpMap); + AddTextureMap (this, table, 'Normal Map', material.normalMap); + AddTextureMap (this, table, 'Emissive Map', material.emissiveMap); + this.Resize (); + } + + Resize () + { + let titleHeight = this.titleDiv.outerHeight (true); + let height = this.parentDiv.height (); + this.contentDiv.outerHeight (height - titleHeight, true); + } + + Clear () + { + this.contentDiv.empty (); + } +}; diff --git a/website/o3dv/toolbar.js b/website/o3dv/toolbar.js index d259020..17d5abf 100644 --- a/website/o3dv/toolbar.js +++ b/website/o3dv/toolbar.js @@ -12,12 +12,13 @@ OV.ToolbarButton = class CreateDomElement (parentDiv) { - this.buttonDiv = $('
    ').addClass ('ov_toolbar_button_div').appendTo (parentDiv); + this.buttonDiv = $('
    ').addClass ('ov_toolbar_button').appendTo (parentDiv); this.buttonImg = $('').addClass ('ov_toolbar_button').appendTo (this.buttonDiv); this.buttonImg.attr ('src', this.image); if (this.onClick !== null) { this.buttonDiv.click (this.onClick); } + this.buttonDiv.attr ('alt', this.imageTitle); OV.InstallTooltip (this.buttonDiv, this.imageTitle); this.Update (); } diff --git a/website/o3dv/utils.js b/website/o3dv/utils.js index b761302..3142df1 100644 --- a/website/o3dv/utils.js +++ b/website/o3dv/utils.js @@ -136,3 +136,15 @@ OV.CreateIconButton = function (iconName, hoverIconName, title, link) } return buttonLink; }; + +OV.CreateInlineColorCircle = function (color) +{ + let hexString = '#' + OV.ColorToHexString (color); + let darkerColor = new OV.Color ( + Math.max (0, color.r - 50), + Math.max (0, color.g - 50), + Math.max (0, color.b - 50) + ); + let darkerColorHexString = '#' + OV.ColorToHexString (darkerColor); + return $('
    ').addClass ('ov_color_circle').css ('background', hexString).css ('border', '1px solid ' + darkerColorHexString); +}; diff --git a/website/o3dv/website.css b/website/o3dv/website.css index f5ac331..ecb1e79 100644 --- a/website/o3dv/website.css +++ b/website/o3dv/website.css @@ -118,7 +118,7 @@ div.main div.main_navigator { - width: 240px; + width: 260px; margin: 10px 0px 10px 10px; overflow: none; float: left; @@ -129,6 +129,14 @@ div.main_viewer float: left; } +div.main_sidebar +{ + width: 260px; + margin: 10px 10px 10px 0px; + overflow: none; + float: right; +} + div.main_viewer canvas { margin: 10px; @@ -167,14 +175,26 @@ div.ov_toolbar user-select: none; } -div.ov_toolbar div.ov_toolbar_button_div +div.ov_toolbar div.ov_toolbar_button { padding: 10px; float: left; cursor: pointer; } -div.ov_toolbar div.ov_toolbar_button_div.selected +div.ov_toolbar div.ov_toolbar_button +{ + padding: 10px; + float: left; + cursor: pointer; +} + +div.ov_toolbar div.ov_toolbar_button.right +{ + float: right; +} + +div.ov_toolbar div.ov_toolbar_button.selected { background: #e1e1e1; } @@ -217,88 +237,7 @@ div.ov_navigator_info_panel border-top: 1px solid #dddddd; } -div.ov_navigator_info_panel div.ov_info_panel_main -{ - margin-top: 5px; -} - -div.ov_navigator_info_panel div.ov_info_panel_content -{ - padding: 5px 0px 0px 5px; -} - -div.ov_navigator_info_panel div.ov_info_box -{ - margin-bottom: 10px; - overflow: auto; -} - -div.ov_navigator_info_panel div.ov_info_box_column -{ - float: left; -} - -div.ov_navigator_info_panel div.ov_info_box_title -{ - margin-bottom: 3px; -} - -div.ov_navigator_info_panel div.ov_info_box_content -{ - font-weight: bold; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -div.ov_navigator_info_panel div.ov_info_box_content_big -{ - font-size: 21px; - font-weight: bold; -} - -div.ov_navigator_info_panel div.ov_info_box_details -{ - font-size: 14px; - padding-left: 10px; -} - -div.ov_navigator_info_panel div.ov_info_box_row -{ - padding: 2px 0px; - overflow: auto; -} - -div.ov_navigator_info_panel div.ov_info_box_row_name -{ - width: 40%; - float: left; -} - -div.ov_navigator_info_panel div.ov_info_box_row_value -{ - font-weight: bold; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -div.ov_navigator_info_panel div.ov_info_box_rgbbox -{ - width : 32px; - height: 16px; - margin-right: 10px; - border: 1px solid #222222; - border-radius: 5px; - float: left; -} - -div.ov_navigator_info_panel div.ov_info_box_rgbtext -{ - font-size: 14px; -} - -div.ov_navigator_info_panel div.ov_info_box_button +div.ov_navigator_info_panel div.ov_navigator_info_button { cursor: pointer; margin-top: 10px; @@ -307,13 +246,13 @@ div.ov_navigator_info_panel div.ov_info_box_button overflow: auto; } -div.ov_navigator_info_panel div.ov_info_box_button_text +div.ov_navigator_info_panel div.ov_navigator_info_button_text { padding: 5px; float: left; } -div.ov_navigator_info_panel img.ov_info_box_button_icon +div.ov_navigator_info_panel img.ov_navigator_info_button_icon { width: 18px; height: 18px; @@ -321,6 +260,35 @@ div.ov_navigator_info_panel img.ov_info_box_button_icon float: right; } +div.ov_sidebar_title +{ + font-weight: bold; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + padding-bottom: 10px; + margin-bottom: 10px; + border-bottom: 1px solid #dddddd; +} + +div.ov_sidebar_title div.ov_sidebar_title_text +{ + float: left; +} + +div.ov_sidebar_title img.ov_sidebar_title_img +{ + width: 18px; + height: 18px; + float: right; + cursor: pointer; +} + +div.ov_sidebar_content +{ + overflow: auto; +} + div.ov_tree_view { user-select: none; @@ -380,9 +348,21 @@ div.ov_tree_view div.ov_tree_view_children margin-left: 28px; } +div.ov_color_circle +{ + background: #ffffff; + border: 1px solid #000000; + width: 14px; + height: 14px; + display: inline-block; + margin-right: 5px; + margin-bottom: -2px; + border-radius: 10px; +} + div.ov_modal_overlay { - + } div.ov_dialog @@ -628,22 +608,6 @@ div.ov_popup border-radius: 5px; } -div.ov_popup div.ov_popup_title -{ - font-weight: bold; - margin-top: 15px; - margin-bottom: 10px; - margin-left: 10px; - margin-right: 10px; -} - -div.ov_popup div.ov_popup_text -{ - margin-bottom: 15px; - margin-left: 10px; - margin-right: 10px; -} - div.ov_popup div.ov_popup_list { max-height: 200px; @@ -660,12 +624,8 @@ div.ov_popup div.ov_popup_list_item cursor: pointer; } -div.ov_popup div.ov_popup_list_item_rgbbox +div.ov_popup div.ov_popup_list_item_icon { - width: 18px; - height: 18px; - margin-right: 5px; - border: 1px solid #222222; float: left; } @@ -697,6 +657,52 @@ div.ov_progress div.ov_progress_text text-align: center; } +div.ov_property_table +{ + +} + +div.ov_property_table_custom +{ + margin-top: 8px; + padding-top: 8px; + border-top: 1px solid #dddddd; +} + +div.ov_property_table div.ov_property_table_row +{ + overflow: auto; +} + +div.ov_property_table div.ov_property_table_cell +{ + padding: 4px 0px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + box-sizing: border-box; +} + +div.ov_property_table div.ov_property_table_name +{ + width: 49%; + padding-right: 2%; + float: left; +} + +div.ov_property_table div.ov_property_table_value +{ + width: 49%; + text-align: right; + float: left; +} + +div.ov_property_table div.ov_property_table_button +{ + color: #3393bd; + cursor: pointer; +} + div.ov_thin_scrollbar { scrollbar-color: #cccccc transparent; @@ -722,7 +728,7 @@ a:hover text-decoration: underline; } -div.ov_toolbar div.ov_toolbar_button_div:hover +div.ov_toolbar div.ov_toolbar_button:hover { background: #c9e5f8; } @@ -747,7 +753,7 @@ div.ov_popup div.ov_popup_list_item:hover background: #e4f4ff; } -div.ov_navigator_info_panel div.ov_info_box_button:hover +div.ov_navigator_info_panel div.ov_navigator_info_button:hover { background: #e4f4ff; } diff --git a/website/o3dv/website.js b/website/o3dv/website.js index e74bdbc..8f6f126 100644 --- a/website/o3dv/website.js +++ b/website/o3dv/website.js @@ -5,8 +5,10 @@ OV.Website = class this.parameters = parameters; this.viewer = new OV.Viewer (); this.hashHandler = new OV.HashHandler (); + this.cookieHandler = new OV.CookieHandler (); this.toolbar = new OV.Toolbar (this.parameters.toolbarDiv); - this.navigator = new OV.Navigator (this.parameters.navigatorDiv); + this.sidebar = new OV.Sidebar (this.parameters.sidebarDiv); + this.navigator = new OV.Navigator (this.parameters.navigatorDiv, this.sidebar); this.importSettings = new OV.ImportSettings (); this.modelLoader = new OV.ThreeModelLoader (); this.highlightMaterial = new THREE.MeshPhongMaterial ({ @@ -19,6 +21,7 @@ OV.Website = class Load () { + let canvas = $('').appendTo (this.parameters.viewerDiv); this.viewer.Init (canvas.get (0)); this.ShowViewer (false); @@ -27,7 +30,9 @@ OV.Website = class this.InitToolbar (); this.InitDragAndDrop (); this.InitModelLoader (); + this.InitSidebar (); this.InitNavigator (); + this.InitCookieConsent (); this.viewer.SetClickHandler (this.OnModelClicked.bind (this)); this.Resize (); @@ -47,18 +52,25 @@ OV.Website = class let headerHeight = parseInt (this.parameters.headerDiv.outerHeight (true), 10); let navigatorWidth = 0; + let sidebarWidth = 0; let safetyMargin = 0; if (!OV.IsSmallWidth ()) { navigatorWidth = parseInt (this.parameters.navigatorDiv.outerWidth (true), 10); + if (this.sidebar.IsVisible ()) { + sidebarWidth = parseInt (this.parameters.sidebarDiv.outerWidth (true), 10); + } safetyMargin = 1; } - let contentWidth = windowWidth - navigatorWidth - safetyMargin; + let contentWidth = windowWidth - navigatorWidth - sidebarWidth - safetyMargin; let contentHeight = windowHeight - headerHeight - safetyMargin; + this.parameters.navigatorDiv.outerHeight (contentHeight, true); + this.parameters.sidebarDiv.outerHeight (contentHeight, true); this.parameters.introDiv.outerHeight (contentHeight, true); this.navigator.Resize (); + this.sidebar.Resize (); this.viewer.Resize (contentWidth, contentHeight); } @@ -71,6 +83,12 @@ OV.Website = class } } + ShowSidebar (show) + { + this.sidebar.Show (show); + this.cookieHandler.SetBoolVal ('ov_show_sidebar', show); + } + ClearModel () { if (this.dialog !== null) { @@ -214,8 +232,16 @@ OV.Website = class if (onlyFullWidth) { button.AddClass ('only_full_width'); } + return button; } + function AddRightButton (toolbar, imageName, imageTitle, onlyFullWidth, onClick) + { + let button = AddButton (toolbar, imageName, imageTitle, onlyFullWidth, onClick); + button.AddClass ('right'); + return button; + } + function AddRadioButton (toolbar, imageNames, imageTitles, selectedIndex, onlyFullWidth, onClick) { let imageData = []; @@ -258,7 +284,7 @@ OV.Website = class }); }); AddSeparator (this.toolbar); - AddButton (this.toolbar, 'fit', 'Fit model to Window', false, function () { + AddButton (this.toolbar, 'fit', 'Fit model to window', false, function () { obj.FitModelToWindow (false); }); AddButton (this.toolbar, 'up_y', 'Set Y axis as up vector', false, function () { @@ -305,6 +331,10 @@ OV.Website = class }); }); } + AddRightButton (this.toolbar, 'details', 'Details panel', true, function () { + obj.ShowSidebar (!obj.sidebar.IsVisible ()); + obj.Resize (); + }); this.parameters.fileInput.on ('change', function (ev) { if (ev.target.files.length > 0) { @@ -354,6 +384,19 @@ OV.Website = class }); } + InitSidebar () + { + let obj = this; + this.sidebar.Init ({ + onClose : function () { + obj.ShowSidebar (false); + obj.Resize (); + } + }); + let show = this.cookieHandler.GetBoolVal ('ov_show_sidebar', true); + this.ShowSidebar (show); + } + InitNavigator () { function GetMeshUserData (viewer, meshIndex) @@ -367,58 +410,19 @@ OV.Website = class return userData; } - function GetBoundingBoxInfo (boundingBox) + function GetMeshesForMaterial (viewer, model, materialIndex) { - if (boundingBox === null) { - return null; - } - return { - min : new OV.Coord3D (boundingBox.min.x, boundingBox.min.y, boundingBox.min.z), - max : new OV.Coord3D (boundingBox.max.x, boundingBox.max.y, boundingBox.max.z) - }; - } - - function GetMaterialInfo (viewer, model, materialIndex) - { - function AddTexture (textureNames, type, texture) - { - if (texture === null) { - return; - } - textureNames.push ({ - type : type, - name : OV.GetFileName (texture.name), - path : texture.name - }); - } - - let material = model.GetMaterial (materialIndex); - let materialInfo = { - name : material.name, - ambient : material.ambient.Clone (), - diffuse : material.diffuse.Clone (), - specular : material.specular.Clone (), - opacity : material.opacity, - textureNames : [], - usedByMeshes : [] - }; - - AddTexture (materialInfo.textureNames, 'Base', material.diffuseMap); - AddTexture (materialInfo.textureNames, 'Specular', material.specularMap); - AddTexture (materialInfo.textureNames, 'Bump', material.bumpMap); - AddTexture (materialInfo.textureNames, 'Normal', material.normalMap); - AddTexture (materialInfo.textureNames, 'Emissive', material.emissiveMap); - + let usedByMeshes = []; viewer.EnumerateMeshesUserData (function (meshUserData) { if (meshUserData.originalMaterials.indexOf (materialIndex) !== -1) { const mesh = model.GetMesh (meshUserData.originalMeshIndex); - materialInfo.usedByMeshes.push ({ + usedByMeshes.push ({ index : meshUserData.originalMeshIndex, name : mesh.GetName () }); } }); - return materialInfo; + return usedByMeshes; } function GetMaterialReferenceInfo (model, materialIndex) @@ -431,50 +435,27 @@ OV.Website = class }; } - function GetMeshInfo (viewer, model, meshIndex) + function GetMaterialsForMesh (viewer, model, meshIndex) { - let result = { - element : null, - usedMaterials : null, - boundingBox : null - }; - - let mesh = model.GetMesh (meshIndex); - result.element = mesh; - + let usedMaterials = []; let userData = GetMeshUserData (viewer, meshIndex); - result.usedMaterials = []; for (let i = 0; i < userData.originalMaterials.length; i++) { const materialIndex = userData.originalMaterials[i]; - result.usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex)); + usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex)); } - result.usedMaterials.sort (function (a, b) { + usedMaterials.sort (function (a, b) { return a.index - b.index; }); - - let boundingBox = viewer.GetBoundingBox (function (meshUserData) { - return meshUserData.originalMeshIndex === meshIndex; - }); - result.boundingBox = GetBoundingBoxInfo (boundingBox); - return result; + return usedMaterials; } - function GetModelInfo (model, viewer) + function GetMaterialsForModel (model) { - let result = { - element : model, - usedMaterials : null, - boundingBox : null - }; - let boundingBox = viewer.GetBoundingBox (function (meshUserData) { - return true; - }); - result.usedMaterials = []; + let usedMaterials = []; for (let materialIndex = 0; materialIndex < model.MaterialCount (); materialIndex++) { - result.usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex)); + usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex)); } - result.boundingBox = GetBoundingBoxInfo (boundingBox); - return result; + return usedMaterials; } let obj = this; @@ -491,15 +472,31 @@ OV.Website = class fitMeshToWindow : function (meshIndex) { obj.FitMeshToWindow (meshIndex); }, - getMaterialInformation : function (materialIndex) { - return GetMaterialInfo (obj.viewer, obj.model, materialIndex); + getMeshesForMaterial : function (materialIndex) { + return GetMeshesForMaterial (obj.viewer, obj.model, materialIndex); }, - getMeshInformation : function (meshIndex) { - return GetMeshInfo (obj.viewer, obj.model, meshIndex); + getMaterialsForMesh : function (meshIndex) { + return GetMaterialsForMesh (obj.viewer, obj.model, meshIndex); }, - getModelInformation : function () { - return GetModelInfo (obj.model, obj.viewer); + getMaterialsForModel : function () { + return GetMaterialsForModel (obj.model); + }, + getModel : function () { + return obj.model; } }); - } + } + + InitCookieConsent () + { + let accepted = this.cookieHandler.GetBoolVal ('ov_cookie_consent', false); + if (accepted) { + return; + } + + let obj = this; + OV.ShowCookieDialog (function () { + obj.cookieHandler.SetBoolVal ('ov_cookie_consent', true); + }); + } };