Qt Quick 3D - Principled Material Example

/**************************************************************************** ** ** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/
import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick3D import QtQuick.Dialogs import Example RowLayout { id: root property Texture targetTexture: null property bool stampMode: false required property url defaultTexture property url stampSource: "" property alias defaultClearColor: drawer.clearColor property bool envMapMode: false GroupBox { title: "Image Source Mode" ColumnLayout { RadioButton { id: noTextureChoice text: "None" checked: true onCheckedChanged: { targetTexture = null } } RadioButton { id: selectTextureChoice text: "Texture" checked: false onCheckedChanged: targetTexture = selectedTexture } RadioButton { id: loadImageChoice text: "Load Image" onCheckedChanged: targetTexture = loadTextureTexture } RadioButton { id: drawerChoice text: "Draw Texture" onCheckedChanged: targetTexture = drawerTexture } } } Item { visible: selectTextureChoice.checked width: 256 height: 256 Image { id: previewImage anchors.fill: parent sourceSize.width: width sourceSize.height: height fillMode: Image.PreserveAspectFit source: root.defaultTexture Texture { id: selectedTexture source: root.defaultTexture mappingMode: envMapMode ? Texture.Environment : Texture.UV } } } Rectangle { id: loadTextureFrame width: 256 height: 256 color: "transparent" border.color: "black" visible: loadImageChoice.checked property url textureSource: "" Text { anchors.centerIn: parent text: "[Load Image]" } Image { anchors.fill: parent sourceSize.width: width sourceSize.height: height fillMode: Image.PreserveAspectFit visible: loadTextureFrame.textureSource !== null source: loadTextureFrame.textureSource } MouseArea { anchors.fill: parent onClicked: { textureSourceDialog.open() } } Texture { id: loadTextureTexture source: loadTextureFrame.textureSource mappingMode: envMapMode ? Texture.Environment : Texture.UV } ImageHelper { id: imageHelper } FileDialog { id: textureSourceDialog title: "Open an Image File" nameFilters: [ imageHelper.getSupportedImageFormatsFilter()] onAccepted: { if (textureSourceDialog.selectedFile !== null) { loadTextureFrame.textureSource = textureSourceDialog.selectedFile } } } } ColumnLayout { visible: drawerChoice.checked Rectangle { width: 260 height: 260 color: "transparent" border.color: "black" Canvas { id: drawer width: 256 height: 256 x: 2 y: 2 property color penColor: "blue" property real penWidth: penWidthSlider.value property bool needsClear: true property color clearColor: "white" property var commands: [] property var stampCommands: [] property bool stampMode: root.stampMode //property point prevPoint : Qt.point(0, 0) onPaint: { let ctx = getContext('2d'); if (needsClear) { ctx.fillStyle = Qt.rgba(clearColor.r, clearColor.g, clearColor.b, clearColor.a); ctx.fillRect(0, 0, width, height) needsClear = false; } if (!stampMode) { ctx.strokeStyle = Qt.rgba(penColor.r, penColor.g, penColor.b, penColor.a) ctx.lineCap = "round" ctx.lineWidth = penWidth; for (let i = 0; i < commands.length; ++i) { let command = commands[i]; ctx.beginPath() ctx.moveTo(command.start.x, command.start.y); ctx.lineTo(command.end.x, command.end.y); ctx.stroke(); } commands = []; } else { for (let i = 0; i < stampCommands.length; ++i) { let stampCommand = stampCommands[i] // get offset let dX = stampCommand.x - stampcursor.width * 0.5 let dY = stampCommand.y - stampcursor.height * 0.5 ctx.drawImage(stampcursor, dX, dY) } stampCommands = []; } } } MouseArea { id: mouseArea anchors.fill: drawer enabled: drawerChoice.checked hoverEnabled: true //acceptedButtons: Qt.LeftButton property bool isDrawing: false property var lastPosition: Qt.point(0, 0) preventStealing: true clip: true Item { id: cursor Rectangle { anchors.centerIn: parent visible: !root.stampMode width: drawer.penWidth height: drawer.penWidth radius: width * 0.5 color: drawer.penColor } Image { id: stampcursor anchors.centerIn: parent visible: root.stampMode source: root.stampSource } } onEntered: cursor.visible = true onExited: cursor.visible = false onPressed: (mouse)=> { if (mouse.button === Qt.LeftButton && !root.stampMode) { lastPosition = Qt.point(mouse.x, mouse.y) isDrawing = true } } onPositionChanged: (mouse)=> { if (isDrawing) { let pos = Qt.point(mouse.x, mouse.y); let command = {"start": lastPosition, "end": pos} drawer.commands.push(command) lastPosition = pos; drawer.requestPaint(); } cursor.x = mouse.x cursor.y = mouse.y } onReleased: (mouse)=> { if (mouse.button === Qt.LeftButton && isDrawing) { let pos = Qt.point(mouse.x, mouse.y); let command = {"start": lastPosition, "end": pos} drawer.commands.push(command) isDrawing = false; drawer.requestPaint(); } else if (stampMode) { drawer.stampCommands.push(Qt.point(mouse.x, mouse.y)); drawer.requestPaint(); } } } } RowLayout { visible: !root.stampMode spacing: 0 Rectangle { id: whiteBrush width: 25 height: 25 color: "white" border.color: "black" MouseArea { anchors.fill: parent onClicked: { drawer.penColor = parent.color; } } } Rectangle { id: blackBrush width: 25 height: 25 color: "black" border.color: "black" MouseArea { anchors.fill: parent onClicked: { drawer.penColor = parent.color; } } } Rectangle { id: redBrush width: 25 height: 25 color: "red" border.color: "black" MouseArea { anchors.fill: parent onClicked: { drawer.penColor = parent.color; } } } Rectangle { id: greenBrush width: 25 height: 25 color: "green" border.color: "black" MouseArea { anchors.fill: parent onClicked: { drawer.penColor = parent.color; } } } Rectangle { id: blueBrush width: 25 height: 25 color: "blue" border.color: "black" MouseArea { anchors.fill: parent onClicked: { drawer.penColor = parent.color; } } } Label { text: " " } Button { text: "Clear" onClicked: { drawer.needsClear = true drawer.requestPaint() } } } RowLayout { visible: !root.stampMode Slider { id: penWidthSlider from: 1 to: 50 value: 5 } Label { Layout.fillWidth: true text: "Pen Width" } } } Texture { id: drawerTexture sourceItem: drawerChoice.checked ? drawer : null mappingMode: envMapMode ? Texture.Environment : Texture.UV } }