Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 096e840098 | |||
| 7601863e3c | |||
| 89b6b2bdfc | |||
| c598aa787b | |||
| 4a451fec3b | |||
| 1ff924eea4 | |||
| 9ce2117a0a | |||
| 2ac94215ee | |||
| 2dac706ca5 | |||
| af950a569e | |||
| 6e900af1fa | |||
| 66741730e0 | |||
| a595b773ba | |||
| da1989d676 | |||
| a89655f7e0 | |||
| a1c53ff063 | |||
| edafa74bac | |||
| 8ca9f46c8a | |||
| f3d100bbcb | |||
| bbe0a8eead | |||
| cfead600a9 | |||
| 5a1c145cf2 | |||
| c34f39d44c | |||
| 9982d55cfb | |||
| 2f2bbd06e6 | |||
| bdbe31b429 | |||
| 7a96022ad3 | |||
| 67b0a961a5 | |||
| 99d7a42c89 | |||
| 70b092050d | |||
| e4994a2612 | |||
| 9c87d944ea | |||
| 801b91b33f | |||
| 051fbd589f | |||
| 20a93d1c10 | |||
| 877b9b7ecb | |||
| 02929d6904 | |||
| 26706c6cbd | |||
| 746dadcc71 | |||
| fa3eec6f10 | |||
| ad6cb36915 | |||
| c5ce7d37a5 | |||
| 611470db41 | |||
| ce9980e408 | |||
| 5f7a6573aa | |||
| a1843dfb50 | |||
| 1f2b77c41c | |||
| 39ef6a70cf | |||
| 5212528156 | |||
| 510ddd1c01 | |||
| 8119083cab | |||
| 307993e648 | |||
| 8230ec2540 | |||
| 0d38a533cc | |||
| f2fdf86e62 | |||
| 4c62bc3005 | |||
| 5d9bfaa19f | |||
| cebdca009c | |||
| 7549927e67 | |||
| 80293fe975 | |||
| 2ba59cbfcc | |||
| 9ed3d1713a | |||
| 76444ced3c | |||
| 8d07def00f | |||
| 3efc7a4c49 | |||
| 267fafb5a4 | |||
| 8b15e39ff7 | |||
| 75f4575813 | |||
| 5e491c622f | |||
| fdcc06c025 | |||
| 7ff7d66c5a | |||
| fbdcf6a419 | |||
| adc64ac2b5 | |||
| dbc36e5553 | |||
| d1114770f7 | |||
| 438a5990b1 | |||
| 5a70dda7bf | |||
| 51fcef121e | |||
| dde7f0d08c | |||
| a73414f22e | |||
| 7e98e1aa28 | |||
| c1924dce25 | |||
| c9e978351d | |||
| 6a35f502b8 | |||
| ce1b5a5fe1 | |||
| 295d0e67c6 | |||
| 789fba6a12 | |||
| d3c0e0699f | |||
| d9afb5574f | |||
| 52a2a153ca |
@@ -0,0 +1,78 @@
|
||||
name: Update issue Status
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
update_issue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get project data
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
|
||||
ORGANIZATION: specklesystems
|
||||
PROJECT_NUMBER: 9
|
||||
run: |
|
||||
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
|
||||
query($org: String!, $number: Int!) {
|
||||
organization(login: $org){
|
||||
projectNext(number: $number) {
|
||||
id
|
||||
fields(first:20) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
settings
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
|
||||
|
||||
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
|
||||
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
|
||||
|
||||
echo "$PROJECT_ID"
|
||||
echo "$STATUS_FIELD_ID"
|
||||
|
||||
echo 'DONE_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .settings | fromjson | .options[] | select(.name== "Done") | .id' project_data.json) >> $GITHUB_ENV
|
||||
echo "$DONE_ID"
|
||||
|
||||
- name: Add Issue to project #it's already in the project, but we do this to get its node id!
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
|
||||
ISSUE_ID: ${{ github.event.issue.node_id }}
|
||||
run: |
|
||||
item_id="$( gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
|
||||
mutation($project:ID!, $id:ID!) {
|
||||
addProjectNextItem(input: {projectId: $project, contentId: $id}) {
|
||||
projectNextItem {
|
||||
id
|
||||
}
|
||||
}
|
||||
}' -f project=$PROJECT_ID -f id=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
|
||||
|
||||
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
|
||||
|
||||
- name: Update Status
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
|
||||
ISSUE_ID: ${{ github.event.issue.node_id }}
|
||||
run: |
|
||||
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
|
||||
mutation($project:ID!, $status:ID!, $id:ID!, $value:String!) {
|
||||
set_status: updateProjectNextItemField(
|
||||
input: {
|
||||
projectId: $project
|
||||
itemId: $id
|
||||
fieldId: $status
|
||||
value: $value
|
||||
}
|
||||
) {
|
||||
projectNextItem {
|
||||
id
|
||||
}
|
||||
}
|
||||
}' -f project=$PROJECT_ID -f status=$STATUS_FIELD_ID -f id=$ITEM_ID -f value=${{ env.DONE_ID }}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
name: Move new issues into Project
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
track_issue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get project data
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
|
||||
ORGANIZATION: specklesystems
|
||||
PROJECT_NUMBER: 9
|
||||
run: |
|
||||
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
|
||||
query($org: String!, $number: Int!) {
|
||||
organization(login: $org){
|
||||
projectNext(number: $number) {
|
||||
id
|
||||
fields(first:20) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
settings
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
|
||||
|
||||
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
|
||||
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
|
||||
|
||||
- name: Add Issue to project
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
|
||||
ISSUE_ID: ${{ github.event.issue.node_id }}
|
||||
run: |
|
||||
item_id="$( gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
|
||||
mutation($project:ID!, $id:ID!) {
|
||||
addProjectNextItem(input: {projectId: $project, contentId: $id}) {
|
||||
projectNextItem {
|
||||
id
|
||||
}
|
||||
}
|
||||
}' -f project=$PROJECT_ID -f id=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
|
||||
|
||||
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
|
||||
+7
-6
@@ -31,9 +31,10 @@
|
||||
*.out
|
||||
*.app
|
||||
*.umap
|
||||
SpeckleUnrealProject/Binaries/
|
||||
SpeckleUnrealProject/Intermediate/
|
||||
SpeckleUnrealProject/Plugins/SpeckleUnreal/Binaries/
|
||||
SpeckleUnrealProject/Plugins/SpeckleUnreal/Intermediate/
|
||||
SpeckleUnrealProject/Saved/
|
||||
SpeckleUnrealProject/.vs/
|
||||
|
||||
Binaries/
|
||||
Intermediate/
|
||||
Saved/
|
||||
|
||||
.idea/
|
||||
.vs/
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"CurrentProjectSetting": "No Configurations"
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"ExpandedNodes": [
|
||||
"",
|
||||
"\\SpeckleUnreal",
|
||||
"\\SpeckleUnreal\\Source"
|
||||
],
|
||||
"PreviewInSolutionExplorer": false
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,21 +1,201 @@
|
||||
MIT License
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Copyright (c) 2020 mobiusnode
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
1. Definitions.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2021 AEC Systems
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@@ -1,29 +1,18 @@
|
||||
# SpeckleUnreal
|
||||
# Speckle Unreal
|
||||
|
||||
[](https://github.com/mobiusnode/SpeckleUnreal) [](http://makeapullrequest.com)
|
||||
[](https://twitter.com/SpeckleSystems) [](https://speckle.community) [](https://speckle.systems) [](https://speckle.guide/dev/)
|
||||
|
||||
Our Team is developing a Speckle plugin and interoperability transport schema for UE4. Our goal is to enable Revit/Dynamo and Rhino/Grasshopper to send + receive geometry to UE4 for visualization. Our current priority is to establish and release a data sender (TO UE4). We’re also working on receiver methods, however our initial focus is on Rhino/Grasshopper to UE4 translation and the attachment of UE4-specific metadata to the core JSON ‘blobs’ in transport.
|
||||
Plugin for Unreal Engine 4 to import objects from Speckle v2.
|
||||
|
||||
In this repository you will find the source code, assets and project settings of the SpeckleUnreal plugin for Unreal Engine app development (Unreal Engine 4.25.1 or newer recommended).
|
||||
|
||||
# Useful Links
|
||||
Use the following links to access resources related to bug reporting, issues, feature requests, and general questions regarding SpeckleUnreal. Future releases may not contain these links & note.
|
||||
Screencast of an example: https://user-images.githubusercontent.com/2551138/114720093-61403e00-9d40-11eb-8045-6e8ca656554d.mp4
|
||||
|
||||
## Speckle Unreal Server
|
||||
https://speckle.mobiusnode.io
|
||||
|
||||
## Discourse Forums (Bugs, Issues, etc.)
|
||||
https://discourse.mobiusnode.io
|
||||
|
||||
## SpeckleUnreal Slack Workspace
|
||||
https://speckle-works-unreal.slack.com
|
||||
|
||||
## YouTub Demo & Tutorial - Getting Started
|
||||
https://bit.ly/3ehHQE6
|
||||
|
||||
## NOTICE
|
||||
|
||||
* Tested on Windows and MacOS and Linux.
|
||||
* Tested on Windows, Unreal Engine v4.26 and Visual Studio Community 2019
|
||||
* Only displays meshes. Breps are converted using their display values.
|
||||
* Does not use the Speckle Kit workflow as conversions all happen in C++.
|
||||
|
||||
@@ -37,20 +26,8 @@ https://bit.ly/3ehHQE6
|
||||
|
||||
We will eventually look to distributing the plugin officially on the Unreal Engine Marketplace but for now you'll need to install the plugin manually like this.
|
||||
|
||||
---
|
||||
## Credits
|
||||
Based off the original Unreal integration for Speckle v1 by Mark and Jak which can be found here: [https://github.com/mobiusnode/SpeckleUnreal](https://github.com/mobiusnode/SpeckleUnreal).
|
||||
|
||||
## Roadmap
|
||||
https://user-images.githubusercontent.com/2551138/114720051-571e3f80-9d40-11eb-9099-d3394747a1d3.mp4
|
||||
|
||||
> Roadmap is subject to change. Last reviewed 10th of July 2020.
|
||||
|
||||
| Version | Defining Feature |
|
||||
| ------- | -------------------------------------------------------------------------------- |
|
||||
| ~0.1~ | ~First prototype release as Unreal Engine plugin~ |
|
||||
| 0.2 | New component workflow and custom materials assigned via inspector~ |
|
||||
| 0.3 | Spawn geometry in transform heirarchy based on layer data |
|
||||
| 0.4 | User login API, get Stream API and no dependency on a local install of Speckle |
|
||||
| 0.5 | Rendering Rule API |
|
||||
| 0.6 | Support Lines, Points, Numbers and Text|
|
||||
| 0.7 | Local caching of Speckle streams |
|
||||
| 0.8 | Implement Sender API |
|
||||
| 1.0 | Production ready (out of preview) |
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,69 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Conversion/ConversionUtils.h"
|
||||
|
||||
FMatrix UConversionUtils::TransformToNative(const TArray<float>& TransformData)
|
||||
{
|
||||
if(TransformData.Num() != 16) return FMatrix::Identity;
|
||||
|
||||
FMatrix TransformMatrix;
|
||||
|
||||
for(int32 Row = 0; Row < 4; Row++)
|
||||
for(int32 Col = 0; Col < 4; Col++)
|
||||
{
|
||||
TransformMatrix.M[Row][Col] = TransformData[Row * 4 + Col];
|
||||
}
|
||||
|
||||
TransformMatrix = TransformMatrix.GetTransposed();
|
||||
|
||||
return TransformMatrix;
|
||||
}
|
||||
|
||||
float UConversionUtils::GetUnitsScaleFactorF(const FString& Units, const float WorldToCentimeters)
|
||||
{
|
||||
static const auto ParseUnits = [](const FString& LUnits) -> float
|
||||
{
|
||||
if (LUnits == "millimeters" || LUnits == "millimeter" || LUnits == "millimetres" || LUnits == "millimetre" || LUnits == "mm")
|
||||
return 0.1;
|
||||
if (LUnits == "centimeters" || LUnits == "centimeter" ||LUnits == "centimetres" || LUnits == "centimetre" || LUnits == "cm")
|
||||
return 1;
|
||||
if (LUnits == "meters" || LUnits == "meter" || LUnits == "metres" || LUnits == "metre" || LUnits == "m")
|
||||
return 100;
|
||||
if (LUnits == "kilometers" || LUnits == "kilometres" || LUnits == "km")
|
||||
return 100000;
|
||||
|
||||
if (LUnits == "inches" || LUnits == "inch" || LUnits == "in")
|
||||
return 2.54;
|
||||
if (LUnits == "feet" || LUnits == "foot" || LUnits == "ft")
|
||||
return 30.48;
|
||||
if (LUnits == "yards" || LUnits == "yard"|| LUnits == "yd")
|
||||
return 91.44;
|
||||
if (LUnits == "miles" || LUnits == "mile" || LUnits == "mi")
|
||||
return 160934.4;
|
||||
|
||||
return 100;
|
||||
};
|
||||
|
||||
return ParseUnits(Units.ToLower()) * WorldToCentimeters;
|
||||
}
|
||||
|
||||
float UConversionUtils::GetUnitsScaleFactor(const FString& Units, const UWorld* World)
|
||||
{
|
||||
int32 WorldToCentimeters;
|
||||
ensureAlways(TryGetWorldUnits(World, WorldToCentimeters));
|
||||
|
||||
return GetUnitsScaleFactorF(Units, WorldToCentimeters);
|
||||
}
|
||||
|
||||
bool UConversionUtils::TryGetWorldUnits(const UWorld* World, int32& OutWorldToCentimeters)
|
||||
{
|
||||
OutWorldToCentimeters = 1;
|
||||
if(!IsValid(World)) return false;
|
||||
|
||||
const AWorldSettings* Settings = World->GetWorldSettings();
|
||||
if(!IsValid(Settings)) return false;
|
||||
|
||||
OutWorldToCentimeters = Settings->WorldToMeters / 10.0;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Conversion/Converters/PointCloudConverter.h"
|
||||
|
||||
#include "LidarPointCloudActor.h"
|
||||
#include "LidarPointCloudComponent.h"
|
||||
#include "SpeckleUnrealManager.h"
|
||||
#include "Objects/PointCloud.h"
|
||||
|
||||
|
||||
UPointCloudConverter::UPointCloudConverter()
|
||||
{
|
||||
SpeckleTypes.Add(UPointCloud::StaticClass());
|
||||
PointCloudActorType = ALidarPointCloudActor::StaticClass();
|
||||
}
|
||||
|
||||
|
||||
AActor* UPointCloudConverter::ConvertToNative_Implementation(const UBase* SpeckleBase, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
const UPointCloud* P = Cast<UPointCloud>(SpeckleBase);
|
||||
|
||||
if(P == nullptr) return nullptr;
|
||||
|
||||
return PointCloudToNative(P, Manager);
|
||||
}
|
||||
|
||||
|
||||
ALidarPointCloudActor* UPointCloudConverter::PointCloudToNative(const UPointCloud* SpecklePointCloud, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
TArray<FLidarPointCloudPoint> LidarPoints;
|
||||
|
||||
LidarPoints.Reserve(SpecklePointCloud->Points.Num());
|
||||
|
||||
for(int i = 0; i < SpecklePointCloud->Points.Num(); i++)
|
||||
{
|
||||
FColor c = SpecklePointCloud->Colors.Num() > i? SpecklePointCloud->Colors[i] : FColor::White;
|
||||
FLidarPointCloudPoint p = FLidarPointCloudPoint(SpecklePointCloud->Points[i], c, true, 0);
|
||||
LidarPoints.Add(p);
|
||||
}
|
||||
|
||||
ULidarPointCloud* PointCloud = NewObject<ULidarPointCloud>();
|
||||
|
||||
PointCloud->Initialize(FBox(SpecklePointCloud->Points));
|
||||
|
||||
PointCloud->InsertPoints(LidarPoints, ELidarPointCloudDuplicateHandling::Ignore, false, FVector::ZeroVector);
|
||||
|
||||
PointCloud->CenterPoints();
|
||||
PointCloud->RefreshBounds();
|
||||
|
||||
return CreateActor(Manager, PointCloud);
|
||||
|
||||
}
|
||||
|
||||
|
||||
ALidarPointCloudActor* UPointCloudConverter::CreateActor(const ASpeckleUnrealManager* Manager, ULidarPointCloud* PointCloudData)
|
||||
{
|
||||
ALidarPointCloudActor* Actor = Manager->GetWorld()->SpawnActor<ALidarPointCloudActor>(PointCloudActorType);
|
||||
Actor->SetPointCloud(PointCloudData);
|
||||
return Actor;
|
||||
}
|
||||
|
||||
|
||||
UBase* UPointCloudConverter::ConvertToSpeckle_Implementation(const UObject* Object, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
const ULidarPointCloudComponent* P = Cast<ULidarPointCloudComponent>(Object);
|
||||
|
||||
if(P == nullptr)
|
||||
{
|
||||
const AActor* A = Cast<AActor>(Object);
|
||||
if(A != nullptr)
|
||||
{
|
||||
P = A->FindComponentByClass<ULidarPointCloudComponent>();
|
||||
}
|
||||
}
|
||||
if(P == nullptr) return nullptr;
|
||||
|
||||
return PointCloudToSpeckle(P, Manager);
|
||||
}
|
||||
|
||||
|
||||
UPointCloud* UPointCloudConverter::PointCloudToSpeckle(const ULidarPointCloudComponent* Object, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
return nullptr; //TODO implement ToSpeckle function
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "Conversion/Converters/ProceduralMeshConverter.h"
|
||||
|
||||
#include "ProceduralMeshComponent.h"
|
||||
#include "StaticMeshDescription.h"
|
||||
#include "SpeckleUnrealManager.h"
|
||||
#include "Objects/Mesh.h"
|
||||
#include "Objects/RenderMaterial.h"
|
||||
|
||||
UProceduralMeshConverter::UProceduralMeshConverter()
|
||||
{
|
||||
SpeckleTypes.Add(UMesh::StaticClass());
|
||||
MeshActorType = AActor::StaticClass();
|
||||
bCreateCollisions = true;
|
||||
}
|
||||
|
||||
AActor* UProceduralMeshConverter::ConvertToNative_Implementation(const UBase* SpeckleBase, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
const UMesh* P = Cast<UMesh>(SpeckleBase);
|
||||
|
||||
if(P == nullptr) return nullptr;
|
||||
|
||||
//No existing mesh was found, try and convert SpeckleMesh
|
||||
UMesh* ScaledMesh = DuplicateObject(P, P->GetOuter(), P->GetFName());
|
||||
ScaledMesh->ApplyUnits(Manager->GetWorld());
|
||||
ScaledMesh->AlignVerticesWithTexCoordsByIndex();
|
||||
|
||||
return MeshToNative(ScaledMesh, Manager);
|
||||
}
|
||||
|
||||
AActor* UProceduralMeshConverter::MeshToNative(const UMesh* SpeckleMesh, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
AActor* MeshActor = CreateActor(Manager, FTransform(SpeckleMesh->GetTransform()));
|
||||
UProceduralMeshComponent* MeshComponent = NewObject<UProceduralMeshComponent>(MeshActor, FName("SpeckleMeshComponent"));
|
||||
MeshComponent->SetupAttachment(MeshActor->GetRootComponent());
|
||||
MeshComponent->RegisterComponent();
|
||||
|
||||
TArray<int32> Faces;
|
||||
|
||||
int32 i = 0;
|
||||
while (i < SpeckleMesh->Faces.Num())
|
||||
{
|
||||
int32 n = SpeckleMesh->Faces[i];
|
||||
if(n < 3) n += 3; // 0 -> 3, 1 -> 4
|
||||
|
||||
if (n == 3) //Triangles
|
||||
{
|
||||
Faces.Add(SpeckleMesh->Faces[i + 3]);
|
||||
Faces.Add(SpeckleMesh->Faces[i + 2]);
|
||||
Faces.Add(SpeckleMesh->Faces[i + 1]);
|
||||
}
|
||||
else if(n == 4) // Quads
|
||||
{
|
||||
Faces.Add(SpeckleMesh->Faces[i + 4]);
|
||||
Faces.Add(SpeckleMesh->Faces[i + 3]);
|
||||
Faces.Add(SpeckleMesh->Faces[i + 1]);
|
||||
|
||||
Faces.Add(SpeckleMesh->Faces[i + 3]);
|
||||
Faces.Add(SpeckleMesh->Faces[i + 2]);
|
||||
Faces.Add(SpeckleMesh->Faces[i + 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// n-gons shall be ignored
|
||||
}
|
||||
|
||||
i += n + 1;
|
||||
}
|
||||
|
||||
TArray<FColor> VertexColors;
|
||||
VertexColors.Reserve(SpeckleMesh->Colors.Num());
|
||||
for(const int32& c : SpeckleMesh->Colors) VertexColors.Add(FColor(c));
|
||||
|
||||
const TArray<FVector> Normals;
|
||||
const TArray<FProcMeshTangent> Tangents;
|
||||
|
||||
MeshComponent->CreateMeshSection(
|
||||
0,
|
||||
SpeckleMesh->GetVerts(),
|
||||
Faces,
|
||||
Normals,
|
||||
SpeckleMesh->GetTextureCoordinates(),
|
||||
VertexColors,
|
||||
Tangents,
|
||||
bCreateCollisions);
|
||||
|
||||
MeshComponent->SetMaterial(0, GetMaterial(SpeckleMesh->RenderMaterial, Manager));
|
||||
|
||||
return MeshActor;
|
||||
}
|
||||
|
||||
AActor* UProceduralMeshConverter::CreateActor(const ASpeckleUnrealManager* Manager, const FTransform& Transform, const FActorSpawnParameters& SpawnParameters)
|
||||
{
|
||||
AActor* Actor = Manager->GetWorld()->SpawnActor<AActor>(MeshActorType, Transform, SpawnParameters);
|
||||
USceneComponent* Scene = NewObject<USceneComponent>(Actor, "Root");
|
||||
Actor->SetRootComponent(Scene);
|
||||
Scene->RegisterComponent();
|
||||
return Actor;
|
||||
}
|
||||
|
||||
|
||||
UMaterialInterface* UProceduralMeshConverter::GetMaterial(const URenderMaterial* SpeckleMaterial, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
UMaterialInterface* ExistingMaterial;
|
||||
if(Manager->TryGetMaterial(SpeckleMaterial, true, ExistingMaterial))
|
||||
return ExistingMaterial; //Return existing material
|
||||
|
||||
UMaterialInterface* MaterialBase = SpeckleMaterial->Opacity >= 1
|
||||
? Manager->BaseMeshOpaqueMaterial
|
||||
: Manager->BaseMeshTransparentMaterial;
|
||||
|
||||
UMaterialInstanceDynamic* DynMaterial = UMaterialInstanceDynamic::Create(MaterialBase, Manager, FName(SpeckleMaterial->Name));
|
||||
|
||||
DynMaterial->SetFlags(RF_Public);
|
||||
|
||||
DynMaterial->SetScalarParameterValue("Opacity", SpeckleMaterial->Opacity);
|
||||
DynMaterial->SetScalarParameterValue("Metallic", SpeckleMaterial->Metalness);
|
||||
DynMaterial->SetScalarParameterValue("Roughness", SpeckleMaterial->Roughness);
|
||||
DynMaterial->SetVectorParameterValue("BaseColor", FColor(SpeckleMaterial->Diffuse));
|
||||
DynMaterial->SetVectorParameterValue("EmissiveColor", FColor(SpeckleMaterial->Emissive));
|
||||
|
||||
Manager->ConvertedMaterials.Add(SpeckleMaterial->Id, DynMaterial);
|
||||
|
||||
return DynMaterial;
|
||||
}
|
||||
|
||||
|
||||
UBase* UProceduralMeshConverter::ConvertToSpeckle_Implementation(const UObject* Object, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
const UProceduralMeshComponent* M = Cast<UProceduralMeshComponent>(Object);
|
||||
|
||||
if(M == nullptr)
|
||||
{
|
||||
const AActor* A = Cast<AActor>(Object);
|
||||
if(A != nullptr)
|
||||
{
|
||||
M = A->FindComponentByClass<UProceduralMeshComponent>();
|
||||
}
|
||||
}
|
||||
if(M == nullptr) return nullptr;
|
||||
|
||||
return MeshToSpeckle(M, Manager);
|
||||
}
|
||||
|
||||
|
||||
UMesh* UProceduralMeshConverter::MeshToSpeckle(const UProceduralMeshComponent* Object, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
return nullptr; //TODO implement ToSpeckle function
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "Conversion/Converters/StaticMeshConverter.h"
|
||||
|
||||
#include "MeshDescriptionBase.h"
|
||||
#include "StaticMeshDescription.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "SpeckleUnrealManager.h"
|
||||
#include "StaticMeshOperations.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "Engine/StaticMeshActor.h"
|
||||
#include "Materials/MaterialInstanceConstant.h"
|
||||
#include "Objects/Mesh.h"
|
||||
#include "Objects/RenderMaterial.h"
|
||||
|
||||
|
||||
UStaticMeshConverter::UStaticMeshConverter()
|
||||
{
|
||||
Transient = false;
|
||||
UseFullBuild = true;
|
||||
BuildSimpleCollision = true;
|
||||
|
||||
MeshActorType = AStaticMeshActor::StaticClass();
|
||||
SpeckleTypes.Add(UMesh::StaticClass());
|
||||
}
|
||||
|
||||
AActor* UStaticMeshConverter::CreateActor(const ASpeckleUnrealManager* Manager, const FTransform& Transform, const FActorSpawnParameters& SpawnParameters)
|
||||
{
|
||||
AActor* Actor = Manager->GetWorld()->SpawnActor<AActor>(AStaticMeshActor::StaticClass(), Transform, SpawnParameters);
|
||||
return Actor;
|
||||
}
|
||||
|
||||
AActor* UStaticMeshConverter::ConvertToNative_Implementation(const UBase* SpeckleBase, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
const FString PackagePath = FPaths::Combine(TEXT("/Game/Speckle"), Manager->StreamID, TEXT("Geometry"), SpeckleBase->Id);
|
||||
UPackage* Package = CreatePackage(*PackagePath);
|
||||
|
||||
const UMesh* SpeckleMesh = Cast<UMesh>(SpeckleBase);
|
||||
if(SpeckleMesh == nullptr) return nullptr;
|
||||
|
||||
//Find existing mesh
|
||||
UStaticMesh* Mesh = Cast<UStaticMesh>(Package->FindAssetInPackage());
|
||||
|
||||
FMatrix ActorTransform = FMatrix::Identity;
|
||||
if(!IsValid(Mesh))
|
||||
{
|
||||
//No existing mesh was found, try and convert SpeckleMesh
|
||||
UMesh* ScaledMesh = DuplicateObject(SpeckleMesh, SpeckleMesh->GetOuter(), SpeckleMesh->GetFName());
|
||||
ScaledMesh->ApplyUnits(Manager->GetWorld());
|
||||
ScaledMesh->AlignVerticesWithTexCoordsByIndex();
|
||||
|
||||
Mesh = MeshToNative(Package, ScaledMesh, Manager);
|
||||
ActorTransform = ScaledMesh->GetTransform();
|
||||
}
|
||||
AActor* Actor = CreateActor(Manager, FTransform(ActorTransform));
|
||||
|
||||
TInlineComponentArray<UStaticMeshComponent*> Components;
|
||||
Actor->GetComponents<UStaticMeshComponent>(Components);
|
||||
|
||||
UStaticMeshComponent* MeshComponent;
|
||||
if(Components.Num() > 0) MeshComponent = Components[0];
|
||||
else
|
||||
{
|
||||
// MeshActorType doesn't have a UStaticMeshComponent, so we will add one
|
||||
MeshComponent = NewObject<UStaticMeshComponent>(Actor, FName("SpeckleMeshComponent"));
|
||||
MeshComponent->SetupAttachment(Actor->GetRootComponent());
|
||||
MeshComponent->RegisterComponent();
|
||||
}
|
||||
|
||||
MeshComponent->SetStaticMesh(Mesh);
|
||||
MeshComponent->SetMaterial(0, GetMaterial(SpeckleMesh->RenderMaterial, Manager));
|
||||
|
||||
return Actor;
|
||||
}
|
||||
|
||||
UStaticMesh* UStaticMeshConverter::MeshToNative(UObject* Outer, const UMesh* SpeckleMesh,
|
||||
ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
const EObjectFlags ObjectFags = Transient? RF_Transient | RF_Public : RF_Public;
|
||||
UStaticMesh* Mesh = NewObject<UStaticMesh>(Outer, FName(SpeckleMesh->Id), ObjectFags);
|
||||
|
||||
Mesh->InitResources();
|
||||
Mesh->SetLightingGuid();
|
||||
|
||||
UStaticMeshDescription* StaticMeshDescription = Mesh->CreateStaticMeshDescription(Outer);
|
||||
FMeshDescription& BaseMeshDescription = StaticMeshDescription->GetMeshDescription();
|
||||
|
||||
//Build Settings
|
||||
#if WITH_EDITOR
|
||||
{
|
||||
FStaticMeshSourceModel& SrcModel = Mesh->AddSourceModel();
|
||||
SrcModel.BuildSettings.bRecomputeNormals = false;
|
||||
SrcModel.BuildSettings.bRecomputeTangents = false;
|
||||
SrcModel.BuildSettings.bRemoveDegenerates = false;
|
||||
SrcModel.BuildSettings.bUseHighPrecisionTangentBasis = false;
|
||||
SrcModel.BuildSettings.bUseFullPrecisionUVs = false;
|
||||
SrcModel.BuildSettings.bGenerateLightmapUVs = GenerateLightmapUV;
|
||||
SrcModel.BuildSettings.SrcLightmapIndex = 0;
|
||||
SrcModel.BuildSettings.DstLightmapIndex = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
UStaticMesh::FBuildMeshDescriptionsParams MeshParams;
|
||||
MeshParams.bBuildSimpleCollision = BuildSimpleCollision;
|
||||
MeshParams.bCommitMeshDescription = true;
|
||||
MeshParams.bMarkPackageDirty = true;
|
||||
MeshParams.bUseHashAsGuid = false;
|
||||
|
||||
//Set Mesh Data
|
||||
UMaterialInterface* Material = GetMaterial(SpeckleMesh->RenderMaterial, Manager);
|
||||
|
||||
const FName MaterialSlotName = Mesh->AddMaterial(Material);;
|
||||
BaseMeshDescription.PolygonGroupAttributes().RegisterAttribute<FName>(MeshAttribute::PolygonGroup::ImportedMaterialSlotName, 1, MaterialSlotName, EMeshAttributeFlags::None);
|
||||
{
|
||||
const size_t NumberOfVertices = SpeckleMesh->GetVertexCount();
|
||||
StaticMeshDescription->ReserveNewVertices(NumberOfVertices);
|
||||
|
||||
TArray<FVertexID> Vertices;
|
||||
Vertices.Reserve(NumberOfVertices);
|
||||
|
||||
for(const FVector VertexPosition : SpeckleMesh->GetVerts())
|
||||
{
|
||||
const FVertexID VertID = StaticMeshDescription->CreateVertex();
|
||||
StaticMeshDescription->SetVertexPosition(VertID, VertexPosition);
|
||||
Vertices.Add(VertID);
|
||||
}
|
||||
|
||||
//Convert Faces
|
||||
const FPolygonGroupID PolygonGroupID = StaticMeshDescription->CreatePolygonGroup();
|
||||
|
||||
StaticMeshDescription->SetPolygonGroupMaterialSlotName(PolygonGroupID, MaterialSlotName);
|
||||
|
||||
StaticMeshDescription->VertexInstanceAttributes().RegisterAttribute<FVector2D>(MeshAttribute::VertexInstance::TextureCoordinate, 2, FVector2D::ZeroVector, EMeshAttributeFlags::None);
|
||||
|
||||
|
||||
StaticMeshDescription->ReserveNewTriangles(SpeckleMesh->Faces.Num() * 3); //Reserve space assuming faces will all be triangles
|
||||
StaticMeshDescription->ReserveNewPolygons(SpeckleMesh->Faces.Num());
|
||||
StaticMeshDescription->ReserveNewVertexInstances(SpeckleMesh->Faces.Num() * 3); //Reserve space assuming faces will all be triangles
|
||||
|
||||
int32 i = 0;
|
||||
while (i < SpeckleMesh->Faces.Num())
|
||||
{
|
||||
int32 n = SpeckleMesh->Faces[i];
|
||||
if(n < 3) n += 3; // 0 -> 3, 1 -> 4
|
||||
|
||||
TArray<FVertexInstanceID> VertexInstances;
|
||||
VertexInstances.Reserve(n);
|
||||
TSet<FVertexID> Verts;
|
||||
Verts.Reserve(n);
|
||||
for(int j = 0; j < n; j ++)
|
||||
{
|
||||
int32 VertIndex = SpeckleMesh->Faces[i + n - j];
|
||||
FVertexID Vert = Vertices[VertIndex];
|
||||
bool AlreadyInSet;
|
||||
Verts.Add(Vert, &AlreadyInSet);
|
||||
|
||||
if(AlreadyInSet)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("Invalid Polygon while creating mesh %s - vertex at index %d appears more than once in a face, duplicate vertices will be ignored"), *SpeckleMesh->Id, VertIndex);
|
||||
continue;
|
||||
}
|
||||
FVertexInstanceID VertexInstance = StaticMeshDescription->CreateVertexInstance(Vert);
|
||||
|
||||
VertexInstances.Add(VertexInstance);
|
||||
|
||||
if(SpeckleMesh->GetTexCoordCount() > VertIndex)
|
||||
StaticMeshDescription->SetVertexInstanceUV(VertexInstance, SpeckleMesh->GetTextureCoordinate(VertIndex));
|
||||
|
||||
//if(SpeckleMesh->VertexColors.Num() > VertIndex)
|
||||
// //TODO set vertex colors
|
||||
}
|
||||
i += n + 1;
|
||||
if(VertexInstances.Num() < 3)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("Invalid Polygon while creating mesh %s - face has fewer than 3 verts, this face will be ignored"), *SpeckleMesh->Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
TArray<FEdgeID> Edges;
|
||||
Edges.Reserve(n);
|
||||
|
||||
const FPolygonID PolygonID = StaticMeshDescription->CreatePolygon(PolygonGroupID, VertexInstances, Edges);
|
||||
|
||||
for (const FEdgeID EdgeID : Edges)
|
||||
{
|
||||
StaticMeshDescription->GetEdgeHardnesses()[EdgeID] = true;
|
||||
}
|
||||
|
||||
StaticMeshDescription->ComputePolygonTriangulation(PolygonID);
|
||||
}
|
||||
|
||||
#if ENGINE_MAJOR_VERSION <= 4
|
||||
BaseMeshDescription.PolygonAttributes().RegisterAttribute<FVector>(MeshAttribute::Polygon::Normal, 1, FVector::ZeroVector, EMeshAttributeFlags::Transient);
|
||||
BaseMeshDescription.PolygonAttributes().RegisterAttribute<FVector>(MeshAttribute::Polygon::Tangent, 1, FVector::ZeroVector, EMeshAttributeFlags::Transient);
|
||||
BaseMeshDescription.PolygonAttributes().RegisterAttribute<FVector>(MeshAttribute::Polygon::Binormal, 1, FVector::ZeroVector, EMeshAttributeFlags::Transient);
|
||||
BaseMeshDescription.PolygonAttributes().RegisterAttribute<FVector>(MeshAttribute::Polygon::Center, 1, FVector::ZeroVector, EMeshAttributeFlags::Transient);
|
||||
FStaticMeshOperations::ComputePolygonTangentsAndNormals(BaseMeshDescription);
|
||||
#else
|
||||
FStaticMeshOperations::ComputeTriangleTangentsAndNormals(BaseMeshDescription);
|
||||
#endif
|
||||
|
||||
FStaticMeshOperations::ComputeTangentsAndNormals(BaseMeshDescription, EComputeNTBsFlags::Normals | EComputeNTBsFlags::Tangents);
|
||||
}
|
||||
|
||||
//Mesh->PreEditChange(nullptr);
|
||||
|
||||
#if ENGINE_MAJOR_VERSION <= 4
|
||||
Mesh->LightMapCoordinateIndex = 1;
|
||||
#else
|
||||
Mesh->SetLightMapCoordinateIndex(1);
|
||||
#endif
|
||||
|
||||
Mesh->BuildFromMeshDescriptions(TArray<const FMeshDescription*>{&BaseMeshDescription}, MeshParams);
|
||||
|
||||
#if WITH_EDITOR
|
||||
if(UseFullBuild) Mesh->Build(true); //This makes conversion time much slower, but is needed for generating lightmap UVs
|
||||
|
||||
if (GIsEditor && !GWorld->HasBegunPlay())
|
||||
{
|
||||
Mesh->MarkPackageDirty();
|
||||
FAssetRegistryModule::AssetCreated(Mesh);
|
||||
}
|
||||
#endif
|
||||
//Mesh->PostEditChange(); //This doesn't seem to be required
|
||||
|
||||
return Mesh;
|
||||
}
|
||||
|
||||
|
||||
UMaterialInterface* UStaticMeshConverter::GetMaterial(const URenderMaterial* SpeckleMaterial, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
if(SpeckleMaterial == nullptr || SpeckleMaterial->Id == "") return Manager->DefaultMeshMaterial; //Material is invalid
|
||||
|
||||
UMaterialInterface* ExistingMaterial;
|
||||
if(Manager->TryGetMaterial(SpeckleMaterial, true, ExistingMaterial))
|
||||
return ExistingMaterial; //Return existing material
|
||||
|
||||
|
||||
UMaterialInterface* MaterialBase = SpeckleMaterial->Opacity >= 1
|
||||
? Manager->BaseMeshOpaqueMaterial
|
||||
: Manager->BaseMeshTransparentMaterial;
|
||||
|
||||
const FString PackagePath = FPaths::Combine(TEXT("/Game/Speckle"), Manager->StreamID, TEXT("Materials"), SpeckleMaterial->Id);
|
||||
UPackage* Package = CreatePackage(*PackagePath);
|
||||
|
||||
|
||||
UMaterialInstance* MaterialInstance;
|
||||
#if WITH_EDITOR
|
||||
if (GIsEditor && !GWorld->HasBegunPlay())
|
||||
{
|
||||
const FName Name = MakeUniqueObjectName(Package, UMaterialInstanceConstant::StaticClass(), FName(SpeckleMaterial->Name));
|
||||
|
||||
//TStrongObjectPtr< UMaterialInstanceConstantFactoryNew > MaterialFact( NewObject< UMaterialInstanceConstantFactoryNew >() );
|
||||
//MaterialFact->InitialParent = MaterialBase;
|
||||
//UMaterialInstanceConstant* ConstMaterial = Cast< UMaterialInstanceConstant >( MaterialFact->FactoryCreateNew( UMaterialInstanceConstant::StaticClass(), Package, Name, RF_Public, nullptr, GWarn ) );
|
||||
UMaterialInstanceConstant* ConstMaterial = NewObject<UMaterialInstanceConstant>(Package, Name, RF_Public);
|
||||
|
||||
MaterialInstance = ConstMaterial;
|
||||
ConstMaterial->SetParentEditorOnly(MaterialBase);
|
||||
ConstMaterial->SetScalarParameterValueEditorOnly(FMaterialParameterInfo("Opacity"), SpeckleMaterial->Opacity);
|
||||
ConstMaterial->SetScalarParameterValueEditorOnly(FMaterialParameterInfo("Metallic"), SpeckleMaterial->Metalness);
|
||||
ConstMaterial->SetScalarParameterValueEditorOnly(FMaterialParameterInfo("Roughness"), SpeckleMaterial->Roughness);
|
||||
ConstMaterial->SetVectorParameterValueEditorOnly(FMaterialParameterInfo("BaseColor"), FColor(SpeckleMaterial->Diffuse));
|
||||
ConstMaterial->SetVectorParameterValueEditorOnly(FMaterialParameterInfo("EmissiveColor"), FColor(SpeckleMaterial->Emissive));
|
||||
|
||||
//ConstMaterial->InitStaticPermutation();
|
||||
|
||||
ConstMaterial->MarkPackageDirty();
|
||||
|
||||
FAssetRegistryModule::AssetCreated(MaterialInstance);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
UMaterialInstanceDynamic* DynMaterial = UMaterialInstanceDynamic::Create(MaterialBase, Package, FName(SpeckleMaterial->Name));
|
||||
MaterialInstance = DynMaterial;
|
||||
|
||||
DynMaterial->SetScalarParameterValue("Opacity", SpeckleMaterial->Opacity);
|
||||
DynMaterial->SetScalarParameterValue("Metallic", SpeckleMaterial->Metalness);
|
||||
DynMaterial->SetScalarParameterValue("Roughness", SpeckleMaterial->Roughness);
|
||||
DynMaterial->SetVectorParameterValue("BaseColor", FColor(SpeckleMaterial->Diffuse));
|
||||
DynMaterial->SetVectorParameterValue("EmissiveColor", FColor(SpeckleMaterial->Emissive));
|
||||
|
||||
DynMaterial->SetFlags(RF_Public);
|
||||
}
|
||||
|
||||
Manager->ConvertedMaterials.Add(SpeckleMaterial->Id, MaterialInstance);
|
||||
|
||||
return MaterialInstance;
|
||||
|
||||
}
|
||||
|
||||
|
||||
UBase* UStaticMeshConverter::ConvertToSpeckle_Implementation(const UObject* Object, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
const UStaticMeshComponent* M = Cast<UStaticMeshComponent>(Object);
|
||||
|
||||
if(M == nullptr)
|
||||
{
|
||||
const AActor* A = Cast<AActor>(Object);
|
||||
if(A != nullptr)
|
||||
{
|
||||
M = A->FindComponentByClass<UStaticMeshComponent>();
|
||||
}
|
||||
}
|
||||
if(M == nullptr) return nullptr;
|
||||
|
||||
return MeshToSpeckle(M, Manager);
|
||||
}
|
||||
|
||||
|
||||
UMesh* UStaticMeshConverter::MeshToSpeckle(const UStaticMeshComponent* Object, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
return nullptr; //TODO implement ToSpeckle function
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Conversion/SpeckleConverterComponent.h"
|
||||
|
||||
#include "SpeckleUnrealManager.h"
|
||||
#include "Conversion/Converters/PointCloudConverter.h"
|
||||
#include "Conversion/Converters/StaticMeshConverter.h"
|
||||
|
||||
|
||||
// Sets default values for this component's properties
|
||||
USpeckleConverterComponent::USpeckleConverterComponent()
|
||||
{
|
||||
PrimaryComponentTick.bCanEverTick = false;
|
||||
|
||||
//TODO consider using an object library for default converters
|
||||
static ConstructorHelpers::FObjectFinder<UStaticMeshConverter> MeshConverter(TEXT("StaticMeshConverter'/SpeckleUnreal/Converters/DefaultStaticMeshConverter.DefaultStaticMeshConverter'"));
|
||||
static ConstructorHelpers::FObjectFinder<UPointCloudConverter> PointCloudConverter(TEXT("PointCloudConverter'/SpeckleUnreal/Converters/DefaultPointCloudConverter.DefaultPointCloudConverter'"));
|
||||
|
||||
//Mesh
|
||||
//Point
|
||||
//Light
|
||||
//BlockDef
|
||||
//BlockInst
|
||||
//Wall
|
||||
//Element
|
||||
|
||||
SpeckleConverters.Add(MeshConverter.Object);
|
||||
SpeckleConverters.Add(PointCloudConverter.Object);
|
||||
//SpeckleConverter.Add(FLightConverter);
|
||||
}
|
||||
|
||||
void USpeckleConverterComponent::OnConvertersChangeHandler()
|
||||
{
|
||||
SpeckleTypeMap.Empty();
|
||||
|
||||
for(int i = 0; i < SpeckleConverters.Num(); i++)
|
||||
{
|
||||
const UObject* Converter = SpeckleConverters[i];
|
||||
if(Converter != nullptr && !Converter->GetClass()->ImplementsInterface(USpeckleTypeConverter::StaticClass()))
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("Converter {%s} is not a valid converter, Expected to implement interface %s"), *Converter->GetClass()->GetName(), *USpeckleTypeConverter::StaticClass()->GetName())
|
||||
SpeckleConverters.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
void USpeckleConverterComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
|
||||
if (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(USpeckleConverterComponent, SpeckleConverters))
|
||||
{
|
||||
OnConvertersChangeHandler();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
UBase* USpeckleConverterComponent::ConvertToSpeckle(UObject* Object)
|
||||
{
|
||||
//TODO implement ToSpeckle
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
AActor* USpeckleConverterComponent::ConvertToNative(const UBase* Object, ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
check(Object != nullptr);
|
||||
const TSubclassOf<UBase> Type = Object->GetClass();
|
||||
UObject* Converter = GetConverter(Type).GetObject();
|
||||
if(Converter == nullptr)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("Skipping Object %s - No conversion functions exist for %s"), *Object->Id, *Type->GetName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FEditorScriptExecutionGuard ScriptGuard;
|
||||
AActor* ReturnObject = ISpeckleTypeConverter::Execute_ConvertToNative(Converter, Object, Manager);
|
||||
|
||||
UE_LOG(LogTemp, Log, TEXT("Converted object of type: %s id: %s "), *Object->Id, *Type->GetName());
|
||||
|
||||
return ReturnObject;
|
||||
}
|
||||
|
||||
TScriptInterface<ISpeckleTypeConverter> USpeckleConverterComponent::GetConverter(const TSubclassOf<UBase> BaseType)
|
||||
{
|
||||
// Check if this SpeckleType has a known converter.
|
||||
if(SpeckleTypeMap.Contains(BaseType))
|
||||
{
|
||||
return SpeckleTypeMap[BaseType];
|
||||
}
|
||||
|
||||
// Try and find one that can convert this SpeckleType.
|
||||
FEditorScriptExecutionGuard ScriptGuard;
|
||||
for(UObject* Converter : SpeckleConverters)
|
||||
{
|
||||
if(Converter == nullptr) continue;
|
||||
|
||||
if(!Converter->GetClass()->ImplementsInterface(USpeckleTypeConverter::StaticClass()))
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("Converter {%s} is not a valid converter, Expected to implement interface {%s}"), *Converter->GetClass()->GetName(), *USpeckleTypeConverter::StaticClass()->GetName())
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ISpeckleTypeConverter::Execute_CanConvertToNative(Converter, BaseType))
|
||||
{
|
||||
//Found a Converter! Save this mapping for next time.
|
||||
SpeckleTypeMap.Add(BaseType, Converter);
|
||||
return Converter;
|
||||
}
|
||||
}
|
||||
|
||||
// SpeckleType has no conversions.
|
||||
SpeckleTypeMap.Add(BaseType, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Objects/BuiltElement.h"
|
||||
|
||||
#include "SpeckleUnrealManager.h"
|
||||
|
||||
|
||||
TArray<FString> UBuiltElement::DisplayValueAliasStrings = {
|
||||
"displayValue",
|
||||
"@displayValue",
|
||||
"displayMesh"
|
||||
"@displayMesh"
|
||||
};
|
||||
|
||||
|
||||
void UBuiltElement::AddDisplayValue(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
UBase* v = Manager->DeserializeBase(Obj);
|
||||
if(v != nullptr) this->DisplayValue.Add(v);
|
||||
}
|
||||
|
||||
void UBuiltElement::Parse(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
Super::Parse(Obj, Manager);
|
||||
|
||||
//Find display values
|
||||
for(const FString& Alias : DisplayValueAliasStrings)
|
||||
{
|
||||
const TSharedPtr<FJsonObject>* SubObjectPtr;
|
||||
if (Obj->TryGetObjectField(Alias, SubObjectPtr))
|
||||
{
|
||||
AddDisplayValue(*SubObjectPtr, Manager);
|
||||
}
|
||||
|
||||
const TArray<TSharedPtr<FJsonValue>>* SubArrayPtr;
|
||||
if (Obj->TryGetArrayField(Alias, SubArrayPtr))
|
||||
{
|
||||
for (const auto& ArrayElement : *SubArrayPtr)
|
||||
{
|
||||
const TSharedPtr<FJsonObject>* ArraySubObjPtr;
|
||||
if (ArrayElement->TryGetObject(ArraySubObjPtr))
|
||||
{
|
||||
AddDisplayValue(*SubObjectPtr, Manager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Objects/Mesh.h"
|
||||
|
||||
#include "SpeckleUnrealManager.h"
|
||||
#include "Conversion/ConversionUtils.h"
|
||||
|
||||
FMatrix UMesh::GetTransform() const
|
||||
{
|
||||
if(Transform.Num() != 16) return FMatrix::Identity;
|
||||
|
||||
FMatrix TransformMatrix;
|
||||
|
||||
for(int32 Row = 0; Row < 4; Row++)
|
||||
for(int32 Col = 0; Col < 4; Col++)
|
||||
{
|
||||
TransformMatrix.M[Row][Col] = Transform[Row * 4 + Col];
|
||||
}
|
||||
|
||||
TransformMatrix = TransformMatrix.GetTransposed();
|
||||
|
||||
return TransformMatrix;
|
||||
}
|
||||
|
||||
void UMesh::SetTransform(const FMatrix& T)
|
||||
{
|
||||
const FMatrix TransformMatrix = T.GetTransposed();
|
||||
|
||||
for(int32 Row = 0; Row < 4; Row++)
|
||||
for(int32 Col = 0; Col < 4; Col++)
|
||||
{
|
||||
Transform[Row * 4 + Col] = TransformMatrix.M[Row][Col];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
FVector UMesh::GetVert(int32 Index) const
|
||||
{
|
||||
Index *= 3;
|
||||
return FVector(
|
||||
Vertices[Index],
|
||||
Vertices[Index + 1],
|
||||
Vertices[Index + 2]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
TArray<FVector> UMesh::GetVerts() const
|
||||
{
|
||||
check(Vertices.Num() % 3 == 0);
|
||||
|
||||
//TODO - Maybe could just use a blit copy assuming 3 floats -> FVector
|
||||
TArray<FVector> VertexVectors;
|
||||
|
||||
const int32 NumberOfVertices = Vertices.Num() / 3;
|
||||
|
||||
VertexVectors.Reserve(NumberOfVertices);
|
||||
|
||||
for (size_t i = 0, j = 0; i < NumberOfVertices; i++, j += 3)
|
||||
{
|
||||
VertexVectors.Add(FVector
|
||||
(
|
||||
Vertices[j],
|
||||
Vertices[j + 1],
|
||||
Vertices[j + 2]
|
||||
));
|
||||
}
|
||||
return VertexVectors;
|
||||
}
|
||||
|
||||
|
||||
FVector2D UMesh::GetTextureCoordinate(int32 Index) const
|
||||
{
|
||||
Index *= 2;
|
||||
return FVector2D(TextureCoordinates[Index], TextureCoordinates[Index + 1]);
|
||||
}
|
||||
|
||||
TArray<FVector2D> UMesh::GetTextureCoordinates() const
|
||||
{
|
||||
//TODO - Maybe could just use a blit copy assuming 2 floats -> FVector2D
|
||||
TArray<FVector2D> TexCoords;
|
||||
|
||||
TexCoords.Reserve(TextureCoordinates.Num() / 2);
|
||||
|
||||
for (int32 i = 0; i + 1 < TexCoords.Num(); i += 2)
|
||||
{
|
||||
TexCoords.Add(FVector2D
|
||||
(
|
||||
TextureCoordinates[i],
|
||||
TextureCoordinates[i + 1]
|
||||
));
|
||||
}
|
||||
return TexCoords;
|
||||
}
|
||||
|
||||
FColor UMesh::GetVertexColor(int32 Index) const
|
||||
{
|
||||
return FColor(Colors[Index]);
|
||||
}
|
||||
|
||||
TArray<FColor> UMesh::GetVertexColors() const
|
||||
{
|
||||
TArray<FColor> VertexColors;
|
||||
|
||||
VertexColors.Reserve(Colors.Num());
|
||||
|
||||
for (int32 i = 0; i + 1 < Colors.Num(); i ++)
|
||||
{
|
||||
VertexColors.Add(FColor(Colors[i]));
|
||||
}
|
||||
|
||||
return VertexColors;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If not already so, this method will align vertices
|
||||
* such that a vertex and its corresponding texture coordinates have the same index.
|
||||
* See "https://github.com/specklesystems/speckle-sharp/blob/main/Objects/Objects/Geometry/Mesh.cs"
|
||||
*/
|
||||
void UMesh::AlignVerticesWithTexCoordsByIndex()
|
||||
{
|
||||
if(TextureCoordinates.Num() == 0) return;
|
||||
if(TextureCoordinates.Num() == Vertices.Num()) return; //Tex-coords already aligned as expected
|
||||
|
||||
TArray<int32> FacesUnique;
|
||||
FacesUnique.Reserve(Faces.Num());
|
||||
TArray<float> VerticesUnique;
|
||||
VerticesUnique.Reserve(TextureCoordinates.Num() * 3);
|
||||
const bool HasColor = Colors.Num() > 0;
|
||||
TArray<int32> ColorsUnique;
|
||||
if(HasColor) ColorsUnique.Reserve(TextureCoordinates.Num());
|
||||
|
||||
int32 NIndex = 0;
|
||||
while(NIndex < Faces.Num())
|
||||
{
|
||||
int32 n = Faces[NIndex];
|
||||
if (n < 3) n += 3; // 0 -> 3, 1 -> 4
|
||||
|
||||
if (NIndex + n >= Faces.Num()) break; //Malformed face list
|
||||
|
||||
FacesUnique.Add(n);
|
||||
|
||||
for (int32 i = 1; i <= n; i++)
|
||||
{
|
||||
const int32 VertIndex = Faces[NIndex + i];
|
||||
const int32 NewVertIndex = VerticesUnique.Num();
|
||||
|
||||
VerticesUnique.Add(Vertices[VertIndex]);
|
||||
|
||||
if(HasColor) ColorsUnique.Add(Colors[NewVertIndex]);
|
||||
FacesUnique.Add(NewVertIndex);
|
||||
}
|
||||
NIndex += n + 1;
|
||||
}
|
||||
|
||||
Vertices = VerticesUnique;
|
||||
Colors = ColorsUnique;
|
||||
Faces = FacesUnique;
|
||||
|
||||
}
|
||||
|
||||
void UMesh::ApplyScaleFactor(const float ScaleFactor)
|
||||
{
|
||||
for (size_t i = 0; i < Vertices.Num(); i++)
|
||||
{
|
||||
Vertices[i] *= ScaleFactor;
|
||||
}
|
||||
|
||||
FMatrix Transform = GetTransform();
|
||||
Transform.ScaleTranslation(FVector(ScaleFactor));
|
||||
|
||||
}
|
||||
|
||||
void UMesh::ApplyUnits(const UWorld* World)
|
||||
{
|
||||
const UWorld* CheckedWorld = IsValid(World)? World : GetWorld();
|
||||
const float ScaleFactor = UConversionUtils::GetUnitsScaleFactor(Units, CheckedWorld);
|
||||
ApplyScaleFactor(ScaleFactor);
|
||||
|
||||
Units = "cm";
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Objects/PointCloud.h"
|
||||
|
||||
#include "SpeckleUnrealManager.h"
|
||||
|
||||
void UPointCloud::Parse(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager)
|
||||
{
|
||||
Super::Parse(Obj, Manager);
|
||||
|
||||
const float ScaleFactor = Manager->ParseScaleFactor(Units);
|
||||
|
||||
//Parse Points
|
||||
{
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectPoints = Manager->CombineChunks(Obj->GetArrayField("points"));
|
||||
|
||||
Points.Reserve(ObjectPoints.Num() / 3);
|
||||
for (int32 i = 2; i < ObjectPoints.Num(); i += 3)
|
||||
{
|
||||
Points.Add(FVector
|
||||
(
|
||||
-ObjectPoints[i - 2].Get()->AsNumber(),
|
||||
ObjectPoints[i - 1].Get()->AsNumber(),
|
||||
ObjectPoints[i].Get()->AsNumber()
|
||||
) * ScaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Parse Colors
|
||||
{
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectColors = Manager->CombineChunks(Obj->GetArrayField("colors"));
|
||||
|
||||
Colors.Reserve(ObjectColors.Num());
|
||||
for (int32 i = 0; i < ObjectColors.Num(); i += 1)
|
||||
{
|
||||
Colors.Add( FColor(ObjectColors[i].Get()->AsNumber()) );
|
||||
}
|
||||
}
|
||||
|
||||
//Parse Sizes
|
||||
{
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectSizes = Manager->CombineChunks(Obj->GetArrayField("sizes"));
|
||||
|
||||
Sizes.Reserve(ObjectSizes.Num());
|
||||
for (int32 i = 0; i < ObjectSizes.Num(); i += 1)
|
||||
{
|
||||
Sizes.Add( ObjectSizes[i].Get()->AsNumber() * ScaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "Objects/RegisteringBase.h"
|
||||
|
||||
#include "Objects/Base.h"
|
||||
|
||||
//TOptional<TMap<FString, TSubclassOf<UBase>>> URegisteringBase::TypeRegistry;
|
||||
TMap<FString, TSubclassOf<UBase>> URegisteringBase::TypeRegistry;
|
||||
|
||||
void URegisteringBase::GenerateTypeRegistry()
|
||||
{
|
||||
//TypeRegistry.Reset();
|
||||
TypeRegistry.Empty();
|
||||
//TypeRegistry = TMap<FString, TSubclassOf<UBase>>();
|
||||
//check(TypeRegistry.IsSet());
|
||||
|
||||
//Find every class : UBase and add to Registry
|
||||
for (TObjectIterator<UClass> It; It; ++It)
|
||||
{
|
||||
const UClass* Class = *It;
|
||||
if (Class->IsChildOf(UBase::StaticClass()) &&
|
||||
!Class->HasAnyClassFlags(CLASS_Abstract))
|
||||
{
|
||||
const FString& SpeckleType = Class->GetDefaultObject<UBase>()->SpeckleType;;
|
||||
|
||||
ensureAlwaysMsgf(!TypeRegistry.Contains(SpeckleType),
|
||||
TEXT("Base class: %s conflicts with: %s for SpeckleType: %s"),
|
||||
*Class->GetName(),
|
||||
*TypeRegistry[SpeckleType]->GetName(),
|
||||
*SpeckleType);
|
||||
|
||||
TypeRegistry.Add(SpeckleType, *It);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TSubclassOf<UBase> URegisteringBase::FindClosestType(const FString& SpeckleType)
|
||||
{
|
||||
FString TypeString(SpeckleType);
|
||||
TSubclassOf<UBase> Type = nullptr;
|
||||
|
||||
while(!TryGetRegisteredType(TypeString, Type))
|
||||
{
|
||||
int32 SplitIndex;
|
||||
if(TypeString.FindLastChar('.', SplitIndex))
|
||||
{
|
||||
TypeString = TypeString.Left(SplitIndex);
|
||||
}
|
||||
else return nullptr;
|
||||
}
|
||||
|
||||
return Type;
|
||||
|
||||
}
|
||||
|
||||
TSubclassOf<UBase> URegisteringBase::GetRegisteredType(const FString& SpeckleType)
|
||||
{
|
||||
TSubclassOf<UBase> Type = nullptr;
|
||||
TryGetRegisteredType(SpeckleType, Type);
|
||||
return Type;
|
||||
}
|
||||
|
||||
bool URegisteringBase::TryGetRegisteredType(const FString& SpeckleType, TSubclassOf<UBase>& OutType)
|
||||
{
|
||||
if(TypeRegistry.Num() == 0) GenerateTypeRegistry();
|
||||
|
||||
|
||||
const bool Contains = TypeRegistry.Contains(SpeckleType);
|
||||
if(Contains)
|
||||
{
|
||||
OutType = *TypeRegistry.Find(SpeckleType);
|
||||
}
|
||||
return Contains;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "SpeckleUnrealActor.h"
|
||||
|
||||
// Sets default values
|
||||
ASpeckleUnrealActor::ASpeckleUnrealActor()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
||||
Scene = CreateDefaultSubobject<USceneComponent>("Root");
|
||||
RootComponent = Scene;
|
||||
Scene->SetMobility(EComponentMobility::Static);
|
||||
}
|
||||
|
||||
|
||||
+3
-6
@@ -3,16 +3,13 @@
|
||||
|
||||
#include "SpeckleUnrealLayer.h"
|
||||
|
||||
ASpeckleUnrealLayer::ASpeckleUnrealLayer()
|
||||
USpeckleUnrealLayer::USpeckleUnrealLayer()
|
||||
{
|
||||
Scene = CreateDefaultSubobject<USceneComponent>("Root");
|
||||
RootComponent = Scene;
|
||||
|
||||
}
|
||||
|
||||
void ASpeckleUnrealLayer::Init(FString NewLayerName, int32 NewStartIndex, int32 NewObjectCount)
|
||||
void USpeckleUnrealLayer::Init(FString NewLayerName, int32 NewStartIndex, int32 NewObjectCount)
|
||||
{
|
||||
SetActorLabel(NewLayerName);
|
||||
|
||||
LayerName = NewLayerName;
|
||||
LayerColor = FLinearColor(FMath::FRandRange(0, 1), FMath::FRandRange(0, 1), FMath::FRandRange(0, 1), 1);
|
||||
StartIndex = NewStartIndex;
|
||||
@@ -0,0 +1,426 @@
|
||||
#include "JsonObjectConverter.h"
|
||||
#include "SpeckleUnrealActor.h"
|
||||
#include "SpeckleUnrealManager.h"
|
||||
#include "Objects/Mesh.h"
|
||||
|
||||
#include "Objects/RenderMaterial.h"
|
||||
|
||||
|
||||
void ASpeckleUnrealManager::ImportObjectFromCache(AActor* AOwner, const TSharedPtr<FJsonObject> SpeckleObject)
|
||||
{
|
||||
{ // Handle Detached Objects
|
||||
TSharedPtr<FJsonObject> DetachedObject;
|
||||
if(ResolveReference(SpeckleObject, DetachedObject))
|
||||
{
|
||||
return ImportObjectFromCache(AOwner, DetachedObject);
|
||||
}
|
||||
}
|
||||
|
||||
const UBase* Base = DeserializeBase(SpeckleObject);
|
||||
if(Base == nullptr)
|
||||
return;
|
||||
|
||||
AActor* Native = Converter->ConvertToNative(Base, this);
|
||||
|
||||
if(IsValid(Native))
|
||||
{
|
||||
|
||||
#if WITH_EDITOR
|
||||
Native->SetActorLabel(FString::Printf(TEXT("%s - %s"), *Base->SpeckleType, *Base->Id));
|
||||
#endif
|
||||
|
||||
Native->AttachToActor(AOwner, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
Native->SetOwner(AOwner);
|
||||
|
||||
InProgressObjectsCache.Add(Native);
|
||||
}
|
||||
else
|
||||
{
|
||||
Native = AOwner;
|
||||
}
|
||||
|
||||
|
||||
//Convert Children
|
||||
for (const auto& Kv : SpeckleObject->Values)
|
||||
{
|
||||
const TSharedPtr<FJsonObject>* SubObjectPtr;
|
||||
if (Kv.Value->TryGetObject(SubObjectPtr))
|
||||
{
|
||||
ImportObjectFromCache(Native, *SubObjectPtr);
|
||||
continue;
|
||||
}
|
||||
|
||||
const TArray<TSharedPtr<FJsonValue>>* SubArrayPtr;
|
||||
if (Kv.Value->TryGetArray(SubArrayPtr))
|
||||
{
|
||||
for (const auto ArrayElement : *SubArrayPtr)
|
||||
{
|
||||
const TSharedPtr<FJsonObject>* ArraySubObjPtr;
|
||||
if (!ArrayElement->TryGetObject(ArraySubObjPtr))
|
||||
continue;
|
||||
ImportObjectFromCache(Native, *ArraySubObjPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ASpeckleUnrealManager::TryGetMaterial(const URenderMaterial* SpeckleMaterial, const bool AcceptMaterialOverride, UMaterialInterface*& OutMaterial)
|
||||
{
|
||||
const auto MaterialID = SpeckleMaterial->Id;
|
||||
|
||||
if(AcceptMaterialOverride)
|
||||
{
|
||||
//Override by id
|
||||
if(MaterialOverridesById.Contains(MaterialID))
|
||||
{
|
||||
OutMaterial = MaterialOverridesById[MaterialID];
|
||||
return true;
|
||||
}
|
||||
//Override by name
|
||||
const FString Name = SpeckleMaterial->Name;
|
||||
for (const UMaterialInterface* Mat : MaterialOverridesByName)
|
||||
{
|
||||
if(Mat->GetName() == Name)
|
||||
{
|
||||
OutMaterial = MaterialOverridesById[MaterialID];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(ConvertedMaterials.Contains(MaterialID))
|
||||
{
|
||||
OutMaterial = ConvertedMaterials[MaterialID];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
UBase* ASpeckleUnrealManager::DeserializeBase(const TSharedPtr<FJsonObject> Obj) const
|
||||
{
|
||||
{ // Handle Detached Objects
|
||||
TSharedPtr<FJsonObject> DetachedObject;
|
||||
if(ResolveReference(Obj, DetachedObject))
|
||||
{
|
||||
return DeserializeBase(DetachedObject);
|
||||
}
|
||||
}
|
||||
|
||||
FString SpeckleType;
|
||||
if (!Obj->TryGetStringField("speckle_type", SpeckleType)) return nullptr;
|
||||
FString ObjectId = "";
|
||||
Obj->TryGetStringField("id", ObjectId);
|
||||
|
||||
// Get the registered type from Base register
|
||||
const TSubclassOf<UBase> ObjectType = UBase::FindClosestType(SpeckleType);
|
||||
|
||||
if(ObjectType == nullptr)
|
||||
{
|
||||
UE_LOG(LogTemp, Verbose, TEXT("SpeckleType: %s is unknown,%t object: %s will be ignored"), *SpeckleType, *ObjectId );
|
||||
return nullptr; //BaseType = UBase::StaticClass();
|
||||
}
|
||||
|
||||
|
||||
//TODO before we create and deserialised a new object, first check if we have already deserialised this object
|
||||
|
||||
//Create instance of the ObjectType
|
||||
UBase* Base = NewObject<UBase>(GetTransientPackage(), ObjectType);
|
||||
|
||||
//Map of all properties with no explicit UProperty to set.
|
||||
//For now we add all values to this map, then remove the ones we find explicit UProperties for.
|
||||
auto DynamicProperties = TMap<FString, TSharedPtr<FJsonValue>>(Obj->Values);
|
||||
|
||||
//Loop through each UProperty in the UBase and try and set its value from the JSON obj
|
||||
for (TFieldIterator<UProperty> It(ObjectType); It; ++It)
|
||||
{
|
||||
FProperty* Property = *It;
|
||||
void* PropertyValueAddress = Property->ContainerPtrToValuePtr<uint8>(Base);
|
||||
|
||||
// Find a json value matching this property name
|
||||
const FString Key = Property->GetName();
|
||||
const TSharedPtr<FJsonValue>* JsonValuePtr = Obj->Values.Find(Key);
|
||||
|
||||
|
||||
//Ensure value is valid
|
||||
if (!JsonValuePtr) continue;
|
||||
TSharedPtr<FJsonValue> JsonValue = *JsonValuePtr;
|
||||
if ( (!JsonValue.IsValid()) || JsonValue->IsNull() ) continue;
|
||||
|
||||
//Handle chunked values!!!!!
|
||||
if (const FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Property))
|
||||
{
|
||||
const TSharedPtr<FJsonObject>* ChunkedObject;
|
||||
FString ChunkedType;
|
||||
if(JsonValue->TryGetObject(ChunkedObject)
|
||||
&& ChunkedObject->operator->()->TryGetStringField("", ChunkedType)
|
||||
&& ChunkedType == "Speckle.Core.Models.DataChunk")
|
||||
{
|
||||
const TArray<TSharedPtr<FJsonValue>>* ChunkedArray;
|
||||
if(JsonValue->TryGetArray(ChunkedArray))
|
||||
{
|
||||
auto Arr = CombineChunks(*ChunkedArray);
|
||||
if()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Check if property is a Speckle Object
|
||||
if (const FObjectProperty* ObjectProperty = CastField<FObjectProperty>(Property))
|
||||
{
|
||||
UBase* SpeckleObject;
|
||||
if(TryParseSpeckleObjectFromJsonProperty(JsonValue, SpeckleObject))
|
||||
{
|
||||
ObjectProperty->SetObjectPropertyValue(PropertyValueAddress, SpeckleObject);
|
||||
DynamicProperties.Remove(Key);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//Handle primitive types
|
||||
if(FJsonObjectConverter::JsonValueToUProperty(JsonValue, Property, PropertyValueAddress, 0, 0))
|
||||
{
|
||||
DynamicProperties.Remove(Key);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("Failed to deserialise a value, object id: %s, property key: %s"), *ObjectId, *Key)
|
||||
}
|
||||
}
|
||||
|
||||
//Find any remaining Speckle objects and add them as children
|
||||
TMap<FString, UBase*> ChildBases;
|
||||
{
|
||||
const auto DynamicPropertiesCopy = TMap<FString, TSharedPtr<FJsonValue>>(DynamicProperties);
|
||||
for(const auto& Kvp : DynamicPropertiesCopy)
|
||||
{
|
||||
UBase* ChildObject;
|
||||
if(TryParseSpeckleObjectFromJsonProperty(Kvp.Value, ChildObject))
|
||||
{
|
||||
DynamicProperties.Remove(Kvp.Key);
|
||||
ChildBases.Add(ChildObject->Id, ChildObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Base->DynamicProperties = DynamicProperties;
|
||||
Base->Children = ChildBases;
|
||||
return Base;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool ASpeckleUnrealManager::TryParseSpeckleObjectFromJsonProperty(const TSharedPtr<FJsonValue> JsonValue, UBase*& OutBase) const
|
||||
{
|
||||
const TSharedPtr<FJsonObject>* JsonObjectPtr;
|
||||
if(JsonValue->TryGetObject(JsonObjectPtr))
|
||||
{
|
||||
TSharedPtr<FJsonObject> JsonObject;
|
||||
if(!ResolveReference(*JsonObjectPtr, JsonObject))
|
||||
JsonObject = *JsonObjectPtr;
|
||||
|
||||
if(JsonObject.IsValid())
|
||||
{
|
||||
//Handle Speckle object types
|
||||
OutBase = DeserializeBase(JsonObject);
|
||||
return IsValid(OutBase);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Test(const TSharedPtr<FJsonValue> JsonValue, const FProperty* Property, UObject* Base)
|
||||
{
|
||||
if (const FNumericProperty* NumericProperty = CastField<FNumericProperty>(Property))
|
||||
{
|
||||
if (NumericProperty->IsFloatingPoint())
|
||||
{
|
||||
NumericProperty->SetFloatingPointPropertyValue(Base, JsonValue->AsNumber());
|
||||
}
|
||||
else if (NumericProperty->IsInteger())
|
||||
{
|
||||
NumericProperty->SetIntPropertyValue(Base, (int64)JsonValue->AsNumber());
|
||||
}
|
||||
}
|
||||
else if (const FBoolProperty* BoolProperty = CastField<FBoolProperty>(Property))
|
||||
{
|
||||
// Export bools as bools
|
||||
BoolProperty->SetPropertyValue(Base, JsonValue->AsBool());
|
||||
}
|
||||
else if (const FStrProperty* StringProperty = CastField<FStrProperty>(Property))
|
||||
{
|
||||
StringProperty->SetPropertyValue(Base, JsonValue->AsString());
|
||||
}
|
||||
else if (const FMapProperty* MapProperty = CastField<FMapProperty>(Property))
|
||||
{
|
||||
|
||||
}
|
||||
else if (const FSetProperty* SetProperty = CastField<FSetProperty>(Property))
|
||||
{
|
||||
|
||||
}
|
||||
else if (const FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Property))
|
||||
{
|
||||
if (JsonValue->Type != EJson::Array) return;
|
||||
|
||||
const TArray< TSharedPtr<FJsonValue> > ArrayValue = JsonValue->AsArray();
|
||||
int32 ArrLen = ArrayValue.Num();
|
||||
|
||||
// make the output array size match
|
||||
|
||||
}
|
||||
else if (const FStructProperty *StructProperty = CastField<FStructProperty>(Property))
|
||||
{
|
||||
|
||||
}
|
||||
else if (const FObjectProperty *ObjectProperty = CastField<FObjectProperty>(Property))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool ASpeckleUnrealManager::HasObject(const FString& Id) const
|
||||
{
|
||||
return SpeckleObjects.Contains(Id);
|
||||
}
|
||||
|
||||
TSharedPtr<FJsonObject, ESPMode::Fast> ASpeckleUnrealManager::GetSpeckleObject(const FString& Id) const
|
||||
{
|
||||
return *SpeckleObjects.Find(Id);
|
||||
}
|
||||
|
||||
bool ASpeckleUnrealManager::ResolveReference(const TSharedPtr<FJsonObject> Object, TSharedPtr<FJsonObject>& OutObject) const
|
||||
{
|
||||
FString SpeckleType;
|
||||
FString ReferenceID;
|
||||
|
||||
if (Object->TryGetStringField("speckle_type", SpeckleType)
|
||||
&& SpeckleType == "reference"
|
||||
&& Object->TryGetStringField("referencedId",ReferenceID))
|
||||
{
|
||||
OutObject = GetSpeckleObject(ReferenceID);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> ASpeckleUnrealManager::CombineChunks(const TArray<TSharedPtr<FJsonValue>>& ArrayField) const
|
||||
{
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectPoints;
|
||||
|
||||
for(int32 i = 0; i < ArrayField.Num(); i++)
|
||||
{
|
||||
FString Index;
|
||||
if(ArrayField[i]->AsObject()->TryGetStringField("referencedId", Index))
|
||||
{
|
||||
const auto Chunk = SpeckleObjects[Index]->GetArrayField("data");
|
||||
ObjectPoints.Append(Chunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ArrayField; //Array was never chunked to begin with
|
||||
}
|
||||
}
|
||||
return ObjectPoints;
|
||||
}
|
||||
|
||||
float ASpeckleUnrealManager::ParseScaleFactor(const FString& Units) const
|
||||
{
|
||||
static const auto ParseUnits = [](const FString& LUnits) -> float
|
||||
{
|
||||
if (LUnits == "millimeters" || LUnits == "millimeter" || LUnits == "millimetres" || LUnits == "millimetre" || LUnits == "mm")
|
||||
return 0.1;
|
||||
if (LUnits == "centimeters" || LUnits == "centimeter" ||LUnits == "centimetres" || LUnits == "centimetre" || LUnits == "cm")
|
||||
return 1;
|
||||
if (LUnits == "meters" || LUnits == "meter" || LUnits == "metres" || LUnits == "metre" || LUnits == "m")
|
||||
return 100;
|
||||
if (LUnits == "kilometers" || LUnits == "kilometres" || LUnits == "km")
|
||||
return 100000;
|
||||
|
||||
if (LUnits == "inches" || LUnits == "inch" || LUnits == "in")
|
||||
return 2.54;
|
||||
if (LUnits == "feet" || LUnits == "foot" || LUnits == "ft")
|
||||
return 30.48;
|
||||
if (LUnits == "yards" || LUnits == "yard"|| LUnits == "yd")
|
||||
return 91.44;
|
||||
if (LUnits == "miles" || LUnits == "mile" || LUnits == "mi")
|
||||
return 160934.4;
|
||||
|
||||
return 100;
|
||||
};
|
||||
|
||||
return ParseUnits(Units.ToLower()) * WorldToCentimeters;
|
||||
}
|
||||
|
||||
|
||||
AActor* ASpeckleUnrealManager::CreateBlockInstance(const TSharedPtr<FJsonObject> Obj)
|
||||
{
|
||||
//Transform
|
||||
const FString Units = Obj->GetStringField("units");
|
||||
const float ScaleFactor = ParseScaleFactor(Units);
|
||||
|
||||
const TArray<TSharedPtr<FJsonValue>>* TransformData;
|
||||
if(!Obj->TryGetArrayField("transform", TransformData)) return nullptr;
|
||||
|
||||
|
||||
FMatrix TransformMatrix;
|
||||
for(int32 Row = 0; Row < 4; Row++)
|
||||
for(int32 Col = 0; Col < 4; Col++)
|
||||
{
|
||||
TransformMatrix.M[Row][Col] = TransformData->operator[](Row * 4 + Col)->AsNumber();
|
||||
}
|
||||
TransformMatrix = TransformMatrix.GetTransposed();
|
||||
TransformMatrix.ScaleTranslation(FVector(ScaleFactor));
|
||||
|
||||
//Block Instance
|
||||
const FString ObjectId = Obj->GetStringField("id"), SpeckleType = Obj->GetStringField("speckle_type");
|
||||
|
||||
ASpeckleUnrealActor* BlockInstance = World->SpawnActor<ASpeckleUnrealActor>(ASpeckleUnrealActor::StaticClass(), FTransform(TransformMatrix));
|
||||
|
||||
|
||||
//Block Definition
|
||||
const TSharedPtr<FJsonObject>* BlockDefinitionReference;
|
||||
if(!Obj->TryGetObjectField("blockDefinition", BlockDefinitionReference)) return nullptr;
|
||||
|
||||
const FString RefID = BlockDefinitionReference->operator->()->GetStringField("referencedId");
|
||||
|
||||
const TSharedPtr<FJsonObject> BlockDefinition = SpeckleObjects[RefID];
|
||||
|
||||
//For now just recreate mesh, eventually we should use instanced static mesh
|
||||
const auto Geometries = BlockDefinition->GetArrayField("geometry");
|
||||
|
||||
for(const auto Child : Geometries)
|
||||
{
|
||||
const TSharedPtr<FJsonObject> MeshReference = Child->AsObject();
|
||||
const FString MeshID = MeshReference->GetStringField("referencedId");
|
||||
|
||||
//It is important that ParentObject is the BlockInstance not the BlockDefinition to keep NativeIDs of meshes unique between Block Instances
|
||||
ImportObjectFromCache(BlockInstance, SpeckleObjects[MeshID]);
|
||||
}
|
||||
|
||||
|
||||
return BlockInstance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
#include "SpeckleUnrealManager.h"
|
||||
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
// Sets default values
|
||||
ASpeckleUnrealManager::ASpeckleUnrealManager()
|
||||
{
|
||||
static ConstructorHelpers::FObjectFinder<UMaterial> SpeckleMaterial(TEXT("Material'/SpeckleUnreal/SpeckleMaterial.SpeckleMaterial'"));
|
||||
static ConstructorHelpers::FObjectFinder<UMaterial> SpeckleGlassMaterial(TEXT("Material'/SpeckleUnreal/SpeckleGlassMaterial.SpeckleGlassMaterial'"));
|
||||
|
||||
//When the object is constructed, Get the HTTP module
|
||||
Http = &FHttpModule::Get();
|
||||
|
||||
SetRootComponent(CreateDefaultSubobject<USceneComponent>("Root"));
|
||||
RootComponent->SetRelativeScale3D(FVector(-1,1,1));
|
||||
RootComponent->SetMobility(EComponentMobility::Static);
|
||||
|
||||
Converter = CreateDefaultSubobject<USpeckleConverterComponent>(FName("Converter"));
|
||||
|
||||
DefaultMeshMaterial = SpeckleMaterial.Object;
|
||||
BaseMeshOpaqueMaterial = SpeckleMaterial.Object;
|
||||
BaseMeshTransparentMaterial = SpeckleGlassMaterial.Object;
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void ASpeckleUnrealManager::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
if (ImportAtRuntime)
|
||||
ImportSpeckleObject();
|
||||
|
||||
}
|
||||
|
||||
/*Import the Speckle object*/
|
||||
void ASpeckleUnrealManager::ImportSpeckleObject()
|
||||
{
|
||||
const FString UserAgent = FString::Printf(TEXT("Unreal Engine (%s) / %d.%d.%d"), *UGameplayStatics::GetPlatformName(), ENGINE_MAJOR_VERSION, ENGINE_MINOR_VERSION, ENGINE_PATCH_VERSION);
|
||||
|
||||
#if !SUPPRESS_SPECKLE_ANALYTICS
|
||||
|
||||
|
||||
const FString HostApplication = FString::Printf(TEXT("Unreal%%20Engine%%20%d"), ENGINE_MAJOR_VERSION);
|
||||
const FString Action = "receive/manual";
|
||||
FString SpeckleUserID = "No%20SUUID";
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
const FString UserPath = UKismetSystemLibrary::GetPlatformUserDir().LeftChop(10); //remove "Documents/"
|
||||
const FString Dir = FString::Printf(TEXT("%sAppData/Roaming/Speckle/suuid"), *UserPath);
|
||||
FFileHelper::LoadFileToString(SpeckleUserID, *Dir);
|
||||
#endif
|
||||
//TODO MACOS
|
||||
|
||||
//Track page view
|
||||
const FString ViewURL = FString::Printf(
|
||||
TEXT("https://speckle.matomo.cloud/matomo.php?idsite=2&rec=1&apiv=1&uid=%s&action_name=%s&url=http://connectors/%s/%s&urlref=http://connectors/%s/%s&_cvar=%%7B%%22hostApplication%%22:%%20%%22%s%%22%%7D"),
|
||||
*SpeckleUserID,
|
||||
*Action,
|
||||
*HostApplication,
|
||||
*Action,
|
||||
*HostApplication,
|
||||
*Action,
|
||||
*HostApplication
|
||||
);
|
||||
|
||||
const FHttpRequestRef ViewTrackingRequest = Http->CreateRequest();
|
||||
ViewTrackingRequest->SetVerb("POST");
|
||||
ViewTrackingRequest->SetURL(ViewURL);
|
||||
ViewTrackingRequest->SetHeader("User-Agent", UserAgent);
|
||||
ViewTrackingRequest->ProcessRequest();
|
||||
|
||||
//Track receive action
|
||||
const FString EventURL = FString::Printf(
|
||||
TEXT("https://speckle.matomo.cloud/matomo.php?idsite=2&rec=1&apiv=1&uid=%s&_cvar=%%7B%%22hostApplication%%22:%%20%%22%s%%22%%7D&e_c=%s&e_a=%s"),
|
||||
*SpeckleUserID,
|
||||
*HostApplication,
|
||||
*HostApplication,
|
||||
*Action
|
||||
);
|
||||
|
||||
const FHttpRequestRef EventTrackingRequest = Http->CreateRequest();
|
||||
EventTrackingRequest->SetVerb("POST");
|
||||
EventTrackingRequest->SetURL(EventURL);
|
||||
EventTrackingRequest->SetHeader("User-Agent", UserAgent);
|
||||
|
||||
EventTrackingRequest->ProcessRequest();
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
const FString url = ServerUrl + "/objects/" + StreamID + "/" + ObjectID;
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, "[Speckle] Downloading: " + url);
|
||||
|
||||
const FHttpRequestRef Request = Http->CreateRequest();
|
||||
|
||||
Request->SetVerb("GET");
|
||||
Request->SetHeader("Accept", TEXT("text/plain"));
|
||||
Request->SetHeader("Authorization", "Bearer " + AuthToken);
|
||||
|
||||
Request->OnProcessRequestComplete().BindUObject(this, &ASpeckleUnrealManager::OnStreamTextResponseReceived);
|
||||
Request->SetURL(url);
|
||||
Request->SetHeader("User-Agent", UserAgent);
|
||||
Request->ProcessRequest();
|
||||
}
|
||||
|
||||
void ASpeckleUnrealManager::OnStreamTextResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
{
|
||||
if (!bWasSuccessful)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Stream Request failed: " + Response->GetContentAsString());
|
||||
return;
|
||||
}
|
||||
auto responseCode = Response->GetResponseCode();
|
||||
if (responseCode != 200)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, FString::Printf(TEXT("Error response. Response code %d"), responseCode));
|
||||
return;
|
||||
}
|
||||
|
||||
FString response = Response->GetContentAsString();
|
||||
|
||||
// ParseIntoArray is very inneficient for large strings.
|
||||
// https://docs.unrealengine.com/en-US/API/Runtime/Core/Containers/FString/ParseIntoArrayLines/index.html
|
||||
// https://answers.unrealengine.com/questions/81697/reading-text-file-line-by-line.html
|
||||
// Can be fixed by setting the size of the array
|
||||
int lineCount = 0;
|
||||
for (const TCHAR* ptr = *response; *ptr; ptr++)
|
||||
if (*ptr == '\n')
|
||||
lineCount++;
|
||||
TArray<FString> lines;
|
||||
lines.Reserve(lineCount);
|
||||
response.ParseIntoArray(lines, TEXT("\n"), true);
|
||||
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, FString::Printf(TEXT("[Speckle] Parsing %d downloaded objects..."), lineCount));
|
||||
|
||||
|
||||
for (const auto& line : lines)
|
||||
{
|
||||
FString objectId, objectJson;
|
||||
if (!line.Split("\t", &objectId, &objectJson))
|
||||
continue;
|
||||
TSharedPtr<FJsonObject> jsonObject;
|
||||
TSharedRef<TJsonReader<>> jsonReader = TJsonReaderFactory<>::Create(objectJson);
|
||||
if (!FJsonSerializer::Deserialize(jsonReader, jsonObject))
|
||||
continue;
|
||||
|
||||
SpeckleObjects.Add(objectId, jsonObject);
|
||||
}
|
||||
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, FString::Printf(TEXT("[Speckle] Converting %d objects..."), lineCount));
|
||||
|
||||
//World Units setup
|
||||
WorldToCentimeters = 1; //Default value of 1uu = 1cm
|
||||
|
||||
AWorldSettings* WorldSettings;
|
||||
if(IsValid(World = GetWorld() )
|
||||
&& IsValid(WorldSettings = World->GetWorldSettings()) )
|
||||
{
|
||||
WorldToCentimeters = WorldSettings->WorldToMeters / 100;
|
||||
}
|
||||
|
||||
|
||||
ImportObjectFromCache(this, SpeckleObjects[ObjectID]);
|
||||
|
||||
for (const auto& m : CreatedObjectsCache)
|
||||
{
|
||||
if(AActor* a = Cast<AActor>(m))
|
||||
a->Destroy();
|
||||
else
|
||||
m->ConditionalBeginDestroy();
|
||||
}
|
||||
|
||||
CreatedObjectsCache = InProgressObjectsCache;
|
||||
InProgressObjectsCache.Empty();
|
||||
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, FString::Printf(TEXT("[Speckle] Objects imported successfully. Created %d Actors"), CreatedObjectsCache.Num()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ASpeckleUnrealManager::DeleteObjects()
|
||||
{
|
||||
ConvertedMaterials.Empty();
|
||||
|
||||
for (const auto& m : CreatedObjectsCache)
|
||||
{
|
||||
if(AActor* a = Cast<AActor>(m))
|
||||
a->Destroy();
|
||||
else
|
||||
m->ConditionalBeginDestroy();
|
||||
|
||||
}
|
||||
|
||||
CreatedObjectsCache.Empty();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "ConversionUtils.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class SPECKLEUNREAL_API UConversionUtils : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Speckle|Conversion Utilities")
|
||||
static FMatrix TransformToNative(const TArray<float>& TransformData);
|
||||
|
||||
//Parses units string into
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure)
|
||||
static float GetUnitsScaleFactorF(const FString& Units, const float WorldToCentimeters = 1);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure)
|
||||
static float GetUnitsScaleFactor(const FString& Units, const UWorld* World = nullptr);
|
||||
|
||||
//Safely try and get the WorldToCentimeters unit scale factor from the given world.
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure)
|
||||
static bool TryGetWorldUnits(const UWorld* World, int32& OutWorldToCentimeters);
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Conversion/SpeckleTypeConverter.h"
|
||||
|
||||
#include "PointCloudConverter.generated.h"
|
||||
|
||||
class ULidarPointCloudComponent;
|
||||
class ALidarPointCloudActor;
|
||||
class ULidarPointCloud;
|
||||
class UPointCloud;
|
||||
|
||||
UCLASS()
|
||||
class SPECKLEUNREAL_API UPointCloudConverter : public UObject, public ISpeckleTypeConverter
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
CONVERTS_SPECKLE_TYPES()
|
||||
|
||||
protected:
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual ALidarPointCloudActor* CreateActor(const ASpeckleUnrealManager* Manager, ULidarPointCloud* PointCloudData);
|
||||
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TSubclassOf<ALidarPointCloudActor> PointCloudActorType;
|
||||
|
||||
UPointCloudConverter();
|
||||
|
||||
virtual AActor* ConvertToNative_Implementation(const UBase* SpeckleBase, ASpeckleUnrealManager* Manager) override;
|
||||
virtual UBase* ConvertToSpeckle_Implementation(const UObject* Object, ASpeckleUnrealManager* Manager) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual ALidarPointCloudActor* PointCloudToNative(const UPointCloud* SpecklePointCloud, ASpeckleUnrealManager* Manager);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual UPointCloud* PointCloudToSpeckle(const ULidarPointCloudComponent* Object, ASpeckleUnrealManager* Manager);
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Conversion/SpeckleTypeConverter.h"
|
||||
|
||||
#include "ProceduralMeshConverter.generated.h"
|
||||
|
||||
class UProceduralMeshComponent;
|
||||
class UMesh;
|
||||
class URenderMaterial;
|
||||
|
||||
UCLASS()
|
||||
class SPECKLEUNREAL_API UProceduralMeshConverter : public UObject, public ISpeckleTypeConverter
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
CONVERTS_SPECKLE_TYPES()
|
||||
|
||||
protected:
|
||||
|
||||
virtual AActor* CreateActor(const ASpeckleUnrealManager* Manager, const FTransform& Transform, const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters());
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TSubclassOf<AActor> MeshActorType;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool bCreateCollisions;
|
||||
|
||||
// Sets default values for this actor's properties
|
||||
UProceduralMeshConverter();
|
||||
|
||||
|
||||
virtual AActor* ConvertToNative_Implementation(const UBase* SpeckleBase, ASpeckleUnrealManager* Manager) override;
|
||||
virtual UBase* ConvertToSpeckle_Implementation(const UObject* Object, ASpeckleUnrealManager* Manager) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual AActor* MeshToNative(const UMesh* SpeckleMesh, ASpeckleUnrealManager* Manager);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual UMaterialInterface* GetMaterial(const URenderMaterial* SpeckleMaterial, ASpeckleUnrealManager* Manager);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual UMesh* MeshToSpeckle(const UProceduralMeshComponent* Object, ASpeckleUnrealManager* Manager);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Conversion/SpeckleTypeConverter.h"
|
||||
|
||||
#include "StaticMeshConverter.generated.h"
|
||||
|
||||
class AStaticMeshActor;
|
||||
class UMesh;
|
||||
class URenderMaterial;
|
||||
|
||||
UCLASS()
|
||||
class SPECKLEUNREAL_API UStaticMeshConverter : public UObject, public ISpeckleTypeConverter
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
CONVERTS_SPECKLE_TYPES()
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TSubclassOf<AActor> MeshActorType;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool UseFullBuild;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool GenerateLightmapUV;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool BuildSimpleCollision;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool Transient;
|
||||
|
||||
protected:
|
||||
|
||||
virtual AActor* CreateActor(const ASpeckleUnrealManager* Manager, const FTransform& Transform, const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters());
|
||||
|
||||
public:
|
||||
// Sets default values for this actor's properties
|
||||
UStaticMeshConverter();
|
||||
|
||||
virtual AActor* ConvertToNative_Implementation(const UBase* SpeckleBase, ASpeckleUnrealManager* Manager) override;
|
||||
|
||||
virtual UBase* ConvertToSpeckle_Implementation(const UObject* Object, ASpeckleUnrealManager* Manager) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual UStaticMesh* MeshToNative(UObject* Outer, const UMesh* SpeckleMesh, ASpeckleUnrealManager* Manager);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual UMesh* MeshToSpeckle(const UStaticMeshComponent* Object, ASpeckleUnrealManager* Manager);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual UMaterialInterface* GetMaterial(const URenderMaterial* SpeckleMaterial, ASpeckleUnrealManager* Manager);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "SpeckleConverterComponent.generated.h"
|
||||
|
||||
class USpeckleTypeConverter;
|
||||
class ASpeckleUnrealManager;
|
||||
class UBase;
|
||||
class ISpeckleTypeConverter;
|
||||
|
||||
/**
|
||||
* This component contains modular conversion functions for converting Speckle Objects <--> Native Unreal Objects.
|
||||
*/
|
||||
UCLASS(ClassGroup=(Speckle), meta=(BlueprintSpawnableComponent))
|
||||
class SPECKLEUNREAL_API USpeckleConverterComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
|
||||
// A lazily initialised mapping of SpeckleType -> converters.
|
||||
TMap<TSubclassOf<UBase>, TScriptInterface<ISpeckleTypeConverter>> SpeckleTypeMap;
|
||||
|
||||
public:
|
||||
|
||||
// Array of converters
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Speckle|Conversion")
|
||||
TArray<UObject*> SpeckleConverters;
|
||||
|
||||
// Sets default values for this component's properties
|
||||
USpeckleConverterComponent();
|
||||
|
||||
// Validates changes to SpeckleConverters, Should be called after modifying SpeckleConverters
|
||||
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion")
|
||||
virtual void OnConvertersChangeHandler();
|
||||
|
||||
#if WITH_EDITOR
|
||||
virtual void PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent) override;
|
||||
#endif
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion")
|
||||
UBase* ConvertToSpeckle(UObject* Object);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion")
|
||||
AActor* ConvertToNative(const UBase* Object, ASpeckleUnrealManager* Manager);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion")
|
||||
TScriptInterface<ISpeckleTypeConverter> GetConverter(const TSubclassOf<UBase> BaseType);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Objects/Base.h"
|
||||
#include "UObject/Interface.h"
|
||||
|
||||
#include "SpeckleTypeConverter.generated.h"
|
||||
|
||||
class UBase;
|
||||
class ASpeckleUnrealManager;
|
||||
|
||||
// This class does not need to be modified.
|
||||
UINTERFACE()
|
||||
class USpeckleTypeConverter : public UInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
/**
|
||||
* Interfaces for object conversion functions (ToSpeckle and ToNative) of a specific (most likely single) native type.
|
||||
*
|
||||
* Classes implementing this function are responsible for converting one or more UBase types
|
||||
* to a native AActor. (ToNative)
|
||||
* And/Or
|
||||
* Converting one or more AActor types to a UBase type.
|
||||
*
|
||||
* Note: This interface is not equivalent to ISpeckleConverter in the .NET SDK.
|
||||
*/
|
||||
class SPECKLEUNREAL_API ISpeckleTypeConverter
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintNativeEvent)
|
||||
bool CanConvertToNative(TSubclassOf<UBase> BaseType);
|
||||
|
||||
/// Returns the type of Base expected for a given SpeckleType
|
||||
UFUNCTION(BlueprintNativeEvent)
|
||||
TSubclassOf<UBase> ToNativeBase(const FString& SpeckleType);
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent)
|
||||
AActor* ConvertToNative(const UBase* SpeckleBase, ASpeckleUnrealManager* Manager);
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent)
|
||||
UBase* ConvertToSpeckle(const UObject* Object, ASpeckleUnrealManager* Manager);
|
||||
};
|
||||
|
||||
#define CONVERTS_SPECKLE_TYPES() \
|
||||
protected: \
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite) \
|
||||
TSet<TSubclassOf<UBase>> SpeckleTypes; \
|
||||
public: \
|
||||
virtual bool CanConvertToNative_Implementation(TSubclassOf<UBase> BaseType) override { return SpeckleTypes.Contains(BaseType); } \
|
||||
private:
|
||||
@@ -0,0 +1,58 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Objects/RegisteringBase.h"
|
||||
#include "Dom/JsonObject.h"
|
||||
|
||||
#include "Base.generated.h"
|
||||
|
||||
class ASpeckleUnrealManager;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class SPECKLEUNREAL_API UBase : public URegisteringBase
|
||||
{
|
||||
public:
|
||||
|
||||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
|
||||
explicit UBase(const wchar_t* SpeckleType): SpeckleType(SpeckleType) {}
|
||||
explicit UBase(const FString& SpeckleType) : SpeckleType(SpeckleType) {}
|
||||
|
||||
public:
|
||||
|
||||
UBase() : SpeckleType("Base") {}
|
||||
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Speckle|Objects")
|
||||
FString Id;
|
||||
|
||||
//UPROPERTY(BlueprintReadOnly)
|
||||
//TMap<FString, FString> Properties; //TODO figure out how I'm going to do custom properties
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Speckle|Objects")
|
||||
FString Units;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Speckle|Objects")
|
||||
FString SpeckleType;
|
||||
|
||||
//TODO this won't be serialised
|
||||
TMap<FString, TSharedPtr<FJsonValue>> DynamicProperties;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Speckle|Objects")
|
||||
TMap<FString, UBase*> Children;
|
||||
|
||||
/// Callback called right before serialization of this object
|
||||
virtual void OnBeforeSerialize();
|
||||
/// Callback called right after deserialization of this object
|
||||
virtual void OnAfterDeserialize();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Base.h"
|
||||
#include "BuiltElement.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class SPECKLEUNREAL_API UBuiltElement : public UBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
protected:
|
||||
static TArray<FString> DisplayValueAliasStrings;
|
||||
void AddDisplayValue(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager);
|
||||
|
||||
public:
|
||||
|
||||
UBuiltElement() : UBase(TEXT("Objects.Elements")) {}
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
|
||||
TArray<UBase*> DisplayValue;
|
||||
|
||||
virtual void Parse(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager) override;
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Base.h"
|
||||
|
||||
#include "Mesh.generated.h"
|
||||
|
||||
class URenderMaterial;
|
||||
class ASpeckleUnrealManager;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class SPECKLEUNREAL_API UMesh : public UBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UMesh() : UBase(TEXT("Objects.Geometry.Mesh")) {}
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
|
||||
TArray<float> Vertices;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
|
||||
TArray<int32> Faces;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
|
||||
TArray<float> TextureCoordinates;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
|
||||
TArray<int32> Colors;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
|
||||
TArray<float> Transform;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
|
||||
URenderMaterial* RenderMaterial;
|
||||
|
||||
public:
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
FVector GetVert(int32 Index) const;
|
||||
UFUNCTION(BlueprintPure)
|
||||
TArray<FVector> GetVerts() const;
|
||||
UFUNCTION(BlueprintPure)
|
||||
int32 GetVertexCount() const { return Vertices.Num() / 3; }
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
FVector2D GetTextureCoordinate(int32 Index) const;
|
||||
UFUNCTION(BlueprintPure)
|
||||
TArray<FVector2D> GetTextureCoordinates() const;
|
||||
UFUNCTION(BlueprintPure)
|
||||
int32 GetTexCoordCount() const { return TextureCoordinates.Num() / 2; }
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
FORCEINLINE FColor GetVertexColor(int32 Index) const;
|
||||
UFUNCTION(BlueprintPure)
|
||||
TArray<FColor> GetVertexColors() const;
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
FMatrix GetTransform() const;
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SetTransform(const FMatrix& T);
|
||||
|
||||
UFUNCTION()
|
||||
virtual void AlignVerticesWithTexCoordsByIndex();
|
||||
|
||||
UFUNCTION()
|
||||
virtual void ApplyScaleFactor(const float ScaleFactor);
|
||||
|
||||
UFUNCTION()
|
||||
virtual void ApplyUnits(const UWorld* World);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Base.h"
|
||||
#include "PointCloud.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class SPECKLEUNREAL_API UPointCloud : public UBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UPointCloud() : UBase(TEXT("Objects.Other.Pointcloud")) {}
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
|
||||
TArray<float> Points;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
|
||||
TArray<int32> Colors;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
|
||||
TArray<float> Sizes;
|
||||
|
||||
virtual void Parse(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager) override;
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "RegisteringBase.generated.h"
|
||||
|
||||
class UBase;
|
||||
|
||||
UCLASS(Abstract)
|
||||
class SPECKLEUNREAL_API URegisteringBase : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
//static TOptional<TMap<FString, TSubclassOf<UBase>>> TypeRegistry;
|
||||
static TMap<FString, TSubclassOf<UBase>> TypeRegistry;
|
||||
|
||||
static void GenerateTypeRegistry();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// Attempts to find the closest registered TSubclassOf<UBase>
|
||||
/// by recursively stripping away a the most specific name specifier from the given SpeckleType
|
||||
/// until a converter is found or the FString is exhausted.
|
||||
///
|
||||
/// Eg. with an input of "Objects.Elements.Wall"
|
||||
/// Will first look for a registered type of "Objects.Elements.Wall"
|
||||
/// If one is not found, will look for "Objects.Elements" etc.
|
||||
/// Returns nullptr if none found.
|
||||
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
|
||||
static TSubclassOf<UBase> FindClosestType(const FString& SpeckleType);
|
||||
|
||||
/// Attempts to find a TSubclassOf<UBase> with a UBase::SpeckleType matching the given SpeckleType param
|
||||
/// Returns nullptr if none found.
|
||||
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
|
||||
static TSubclassOf<UBase> GetRegisteredType(const FString& SpeckleType);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
|
||||
static bool TryGetRegisteredType(const FString& SpeckleType, TSubclassOf<UBase>& OutType);
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Objects/Base.h"
|
||||
|
||||
#include "RenderMaterial.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class SPECKLEUNREAL_API URenderMaterial : public UBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
URenderMaterial() : UBase(TEXT("Objects.Other.RenderMaterial")) {}
|
||||
|
||||
UPROPERTY()
|
||||
FString Name;
|
||||
|
||||
UPROPERTY()
|
||||
double Opacity = 1;
|
||||
|
||||
UPROPERTY()
|
||||
double Metalness = 0;
|
||||
|
||||
UPROPERTY()
|
||||
double Roughness = 1;
|
||||
|
||||
UPROPERTY()
|
||||
int32 Diffuse = FColor{221,221,221};
|
||||
|
||||
|
||||
|
||||
UPROPERTY()
|
||||
int32 Emissive = FLinearColor::Black;
|
||||
|
||||
virtual void Parse(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager) override
|
||||
{
|
||||
Super::Parse(Obj, Manager);
|
||||
|
||||
Obj->TryGetStringField("name", Name);
|
||||
Obj->TryGetNumberField("opacity", Opacity);
|
||||
Obj->TryGetNumberField("metalness", Metalness);
|
||||
Obj->TryGetNumberField("roughness", Roughness);
|
||||
|
||||
int32 ARGB;
|
||||
if(Obj->TryGetNumberField("diffuse", ARGB))
|
||||
Diffuse = FColor(ARGB);
|
||||
|
||||
if(Obj->TryGetNumberField("emissive", ARGB))
|
||||
Emissive = FColor(ARGB);
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "BaseObjectSerializer.generated.h"
|
||||
|
||||
class UBase;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class SPECKLEUNREAL_API UBaseObjectSerializer : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
//UFUNCTION()
|
||||
//UBase* DeserialiseBase();
|
||||
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "SpeckleUnrealActor.generated.h"
|
||||
|
||||
class UMeshDescriptionBase;
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class SPECKLEUNREAL_API ASpeckleUnrealActor : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
USceneComponent* Scene;
|
||||
|
||||
// Sets default values for this actor's properties
|
||||
ASpeckleUnrealActor();
|
||||
|
||||
};
|
||||
+3
-6
@@ -3,21 +3,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "UObject/NoExportTypes.h"
|
||||
#include "SpeckleUnrealLayer.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(BlueprintType)
|
||||
class SPECKLEUNREAL_API ASpeckleUnrealLayer : public AActor
|
||||
class SPECKLEUNREAL_API USpeckleUnrealLayer : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
USceneComponent* Scene;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Speckle")
|
||||
FString LayerName;
|
||||
|
||||
@@ -30,7 +27,7 @@ public:
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Speckle")
|
||||
int32 ObjectCount;
|
||||
|
||||
ASpeckleUnrealLayer();
|
||||
USpeckleUnrealLayer();
|
||||
|
||||
void Init(FString NewLayerName, int32 NewStartIndex, int32 NewObjectCount);
|
||||
};
|
||||
@@ -0,0 +1,137 @@
|
||||
#pragma once
|
||||
|
||||
// json manipulation
|
||||
#include "Dom/JsonObject.h"
|
||||
#include "Dom/JsonValue.h"
|
||||
|
||||
// web requests
|
||||
#include "Runtime/Online/HTTP/Public/Http.h"
|
||||
|
||||
#include "SpeckleUnrealLayer.h"
|
||||
#include "Conversion/SpeckleConverterComponent.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "SpeckleUnrealManager.generated.h"
|
||||
|
||||
|
||||
class URenderMaterial;
|
||||
|
||||
UCLASS(ClassGroup=(Speckle), BlueprintType)
|
||||
class SPECKLEUNREAL_API ASpeckleUnrealManager : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
FHttpModule* Http;
|
||||
|
||||
/* The actual HTTP call */
|
||||
UFUNCTION(CallInEditor, Category = "Speckle")
|
||||
void ImportSpeckleObject();
|
||||
|
||||
UFUNCTION(CallInEditor, Category = "Speckle")
|
||||
void DeleteObjects();
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
USpeckleConverterComponent* Converter;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString ServerUrl {
|
||||
"https://speckle.xyz"
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString StreamID {
|
||||
""
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString ObjectID {
|
||||
""
|
||||
};
|
||||
|
||||
/** A Personal Access Token can be created from your Speckle Profile page (Treat tokens like passwords, do not share publicly) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString AuthToken {
|
||||
""
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
bool ImportAtRuntime;
|
||||
|
||||
|
||||
/** Material to be applied to meshes when no RenderMaterial can be converted */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle|Materials")
|
||||
UMaterialInterface* DefaultMeshMaterial;
|
||||
|
||||
/** Material Parent for converted opaque materials*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle|Materials")
|
||||
UMaterialInterface* BaseMeshOpaqueMaterial;
|
||||
|
||||
/** Material Parent for converted materials with an opacity less than one */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle|Materials")
|
||||
UMaterialInterface* BaseMeshTransparentMaterial;
|
||||
|
||||
/** When generating meshes, materials in this TMap will be used instead of converted ones if the key matches the ID of the Object's RenderMaterial. (Takes priority over name matching)*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle|Materials|Overrides", DisplayName = "By Speckle ID")
|
||||
TMap<FString, UMaterialInterface*> MaterialOverridesById;
|
||||
|
||||
/** When generating meshes, materials in this TSet will be used instead of converted ones if the material name matches the name of the Object's RenderMaterial. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle|Materials|Overrides", DisplayName = "By Name")
|
||||
TSet<UMaterialInterface*> MaterialOverridesByName;
|
||||
|
||||
/** Materials converted from stream RenderMaterial objects */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Speckle|Materials")
|
||||
TMap<FString, UMaterialInterface*> ConvertedMaterials;
|
||||
|
||||
|
||||
void OnStreamTextResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
|
||||
// Sets default values for this actor's properties
|
||||
ASpeckleUnrealManager();
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> CombineChunks(const TArray<TSharedPtr<FJsonValue>>& ArrayField) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure)
|
||||
float ParseScaleFactor(const FString& Units) const;
|
||||
|
||||
//TODO move to conversion functions
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool TryGetMaterial(const URenderMaterial* SpeckleMaterial, bool AcceptMaterialOverride,
|
||||
UMaterialInterface*& OutMaterial);
|
||||
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure)
|
||||
bool HasObject(const FString& Id) const;
|
||||
|
||||
UBase* DeserializeBase(const TSharedPtr<FJsonObject> Obj) const;
|
||||
bool ResolveReference(const TSharedPtr<FJsonObject> Object, TSharedPtr<FJsonObject>& OutObject) const;
|
||||
|
||||
TSharedPtr<FJsonObject, ESPMode::Fast> GetSpeckleObject(const FString& Id) const;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
UWorld* World;
|
||||
|
||||
float WorldToCentimeters;
|
||||
|
||||
|
||||
bool TryParseSpeckleObjectFromJsonProperty(const TSharedPtr<FJsonValue> JsonValue, UBase*& OutBase) const;
|
||||
|
||||
TMap<FString, TSharedPtr<FJsonObject>> SpeckleObjects;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<UObject*> CreatedObjectsCache;
|
||||
TArray<UObject*> InProgressObjectsCache;
|
||||
|
||||
|
||||
void ImportObjectFromCache(AActor* AOwner, const TSharedPtr<FJsonObject> SpeckleObject);
|
||||
|
||||
//AActor* CreateMesh(const TSharedPtr<FJsonObject> Obj, const TSharedPtr<FJsonObject> Parent = nullptr);
|
||||
AActor* CreateBlockInstance(const TSharedPtr<FJsonObject> Obj);
|
||||
//AActor* CreatePointCloud(const TSharedPtr<FJsonObject> Obj);
|
||||
|
||||
};
|
||||
+11
-8
@@ -1,5 +1,3 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class SpeckleUnreal : ModuleRules
|
||||
@@ -8,18 +6,20 @@ public class SpeckleUnreal : ModuleRules
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDefinitions.Add("SUPPRESS_SPECKLE_ANALYTICS=0");
|
||||
|
||||
PublicIncludePaths.AddRange(
|
||||
new string[] {
|
||||
// ... add public include paths required here ...
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
|
||||
PrivateIncludePaths.AddRange(
|
||||
new string[] {
|
||||
// ... add other private include paths required here ...
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
@@ -29,10 +29,13 @@ public class SpeckleUnreal : ModuleRules
|
||||
"Http",
|
||||
"Json",
|
||||
"JsonUtilities",
|
||||
"ProceduralMeshComponent"
|
||||
"ProceduralMeshComponent",
|
||||
"MeshDescription",
|
||||
"StaticMeshDescription",
|
||||
"LidarPointCloudRuntime",
|
||||
// ... add other public dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
@@ -44,7 +47,7 @@ public class SpeckleUnreal : ModuleRules
|
||||
"SlateCore",
|
||||
// ... add private dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
|
||||
DynamicallyLoadedModuleNames.AddRange(
|
||||
@@ -52,6 +55,6 @@ public class SpeckleUnreal : ModuleRules
|
||||
{
|
||||
// ... add any modules that your module loads dynamically here ...
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Conversion/ConverterFactory.h"
|
||||
|
||||
#include "SpeckleUnrealEditorModule.h"
|
||||
|
||||
|
||||
UConverterFactory::UConverterFactory(UClass* SupportedClass)
|
||||
{
|
||||
bCreateNew = true;
|
||||
bEditAfterNew = true;
|
||||
this->SupportedClass = SupportedClass;
|
||||
}
|
||||
|
||||
uint32 UConverterFactory::GetMenuCategories() const
|
||||
{
|
||||
static const uint32 SpeckleCategory = FModuleManager::LoadModuleChecked<FSpeckleUnrealEditorModule>("SpeckleUnrealEditor").GetSpeckleAssetCategory();
|
||||
return SpeckleCategory;
|
||||
}
|
||||
|
||||
|
||||
UObject* UConverterFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags,
|
||||
UObject* Context, FFeedbackContext* Warn)
|
||||
{
|
||||
UObject* NewObjectAsset = NewObject<UObject>(InParent, Class, Name, Flags);
|
||||
return NewObjectAsset;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "SpeckleUnrealEditorModule.h"
|
||||
|
||||
#include "AssetToolsModule.h"
|
||||
#include "IAssetTools.h"
|
||||
|
||||
#include "Conversion/ConverterActions.h"
|
||||
#include "Conversion/ConverterFactory.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FSpeckleUnrealEditorModule"
|
||||
|
||||
uint32 FSpeckleUnrealEditorModule::GetSpeckleAssetCategory() const
|
||||
{
|
||||
return SpeckleAssetCategoryBit;
|
||||
}
|
||||
|
||||
void FSpeckleUnrealEditorModule::StartupModule()
|
||||
{
|
||||
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
|
||||
#if WITH_EDITOR
|
||||
if (GIsEditor)
|
||||
{
|
||||
IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
|
||||
|
||||
// Register Speckle Category
|
||||
SpeckleAssetCategoryBit = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Speckle")), LOCTEXT("SpeckleCategoryText","Speckle"));
|
||||
|
||||
// Finds all class definitions : UConverterFactory and creates a FConverterActions for their supported class.
|
||||
// See UAssetToolsImpl::GetNewAssetFactories() for reference
|
||||
for (TObjectIterator<UClass> It; It; ++It)
|
||||
{
|
||||
const UClass* Class = *It;
|
||||
if (Class->IsChildOf(UConverterFactory::StaticClass()) &&
|
||||
!Class->HasAnyClassFlags(CLASS_Abstract))
|
||||
{
|
||||
const UConverterFactory* Factory = Class->GetDefaultObject<UConverterFactory>();
|
||||
|
||||
if (Factory->ShouldShowInNewMenu() &&
|
||||
ensure(!Factory->GetDisplayName().IsEmpty()))
|
||||
{
|
||||
AssetTools.RegisterAssetTypeActions(MakeShareable(new FConverterActions(Factory->SupportedClass, SpeckleAssetCategoryBit)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FSpeckleUnrealEditorModule::ShutdownModule()
|
||||
{
|
||||
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
|
||||
// we call this function before unloading the module.
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FSpeckleUnrealEditorModule, SpeckleUnrealEditor)
|
||||
@@ -0,0 +1,31 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
#include "AssetTypeActions_Base.h"
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class FConverterActions : public FAssetTypeActions_Base
|
||||
{
|
||||
private:
|
||||
UClass* SupportedClass;
|
||||
uint32 Category;
|
||||
|
||||
public:
|
||||
explicit FConverterActions(UClass* SupportedClass, uint32 Category)
|
||||
{
|
||||
this->SupportedClass = SupportedClass;
|
||||
this->Category = Category;
|
||||
}
|
||||
|
||||
// IAssetTypeActions Implementation
|
||||
virtual FText GetName() const override { return SupportedClass->GetDisplayNameText(); }
|
||||
virtual UClass* GetSupportedClass() const override { return SupportedClass; }
|
||||
virtual FColor GetTypeColor() const override { return FColor(59, 130, 246); }
|
||||
virtual bool CanLocalize() const override { return false; }
|
||||
|
||||
virtual uint32 GetCategories() override { return Category; }
|
||||
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Factories/Factory.h"
|
||||
#include "Conversion/Converters/ProceduralMeshConverter.h"
|
||||
#include "Conversion/Converters/StaticMeshConverter.h"
|
||||
#include "Conversion/Converters/PointCloudConverter.h"
|
||||
|
||||
#include "ConverterFactory.generated.h"
|
||||
|
||||
/**
|
||||
* This class is designed to reduce the boiler plate required to define a UFactory for ISpeckleTypeConverter types.
|
||||
*
|
||||
* For each ISpeckleTypeConverter we want to appear in the "Create Advanced Asset" context menu
|
||||
* A class definition : UConverterFactory should be created (see below examples)
|
||||
*
|
||||
* A FConverterAction : FAssetTypeActions_Base instance will automatically be created by
|
||||
* FSpeckleUnrealEditorModule::StartupModule for each class definition : UConverterFactory.
|
||||
* So we don't need to worry about manually registering the SupportedClass types with FAssetToolsModule.
|
||||
*/
|
||||
UCLASS(abstract)
|
||||
class SPECKLEUNREALEDITOR_API UConverterFactory : public UFactory
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
explicit UConverterFactory(UClass* SupportedClass);
|
||||
|
||||
public:
|
||||
UConverterFactory() : Super() {}
|
||||
|
||||
virtual uint32 GetMenuCategories() const override;
|
||||
|
||||
virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class SPECKLEUNREALEDITOR_API UStaticMeshConverterFactory : public UConverterFactory
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UStaticMeshConverterFactory() : Super( UStaticMeshConverter::StaticClass() ) { }
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class SPECKLEUNREALEDITOR_API UProceduralMeshConverterFactory : public UConverterFactory
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UProceduralMeshConverterFactory() : Super( UProceduralMeshConverter::StaticClass() ) { }
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class SPECKLEUNREALEDITOR_API UPointCloudConverterFactory : public UConverterFactory
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UPointCloudConverterFactory() : Super( UPointCloudConverter::StaticClass() ) { }
|
||||
};
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
class FSpeckleUnrealEditorModule : public IModuleInterface
|
||||
{
|
||||
|
||||
#if WITH_EDITOR
|
||||
protected:
|
||||
uint32 SpeckleAssetCategoryBit = 0;
|
||||
public:
|
||||
virtual uint32 GetSpeckleAssetCategory() const;
|
||||
#endif
|
||||
|
||||
public:
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class SpeckleUnrealEditor : ModuleRules
|
||||
{
|
||||
public SpeckleUnrealEditor(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicIncludePaths.AddRange(
|
||||
new string[] {
|
||||
// ... add public include paths required here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PrivateIncludePaths.AddRange(
|
||||
new string[] {
|
||||
// ... add other private include paths required here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
"Http",
|
||||
"Json",
|
||||
"JsonUtilities",
|
||||
"UnrealEd",
|
||||
"SpeckleUnreal",
|
||||
// ... add other public dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
// ... add private dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
DynamicallyLoadedModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
// ... add any modules that your module loads dynamically here ...
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
+12
-3
@@ -5,9 +5,9 @@
|
||||
"FriendlyName": "SpeckleUnreal",
|
||||
"Description": "Speckle is an open source data platform for Architecture, Engineering, and Construction. It has been open sourced under the MIT license, is customizable, and available in the cloud or via a self-hosted server. It allows users to exchange data between various AEC modelling and content creation platforms.",
|
||||
"Category": "AEC",
|
||||
"CreatedBy": "Mobius Node",
|
||||
"CreatedByURL": "https://www.mobiusnode.io/",
|
||||
"DocsURL": "https://github.com/mobiusnode/SpeckleUnreal",
|
||||
"CreatedBy": "Speckle",
|
||||
"CreatedByURL": "https://speckle.systems/",
|
||||
"DocsURL": "https://github.com/specklesystems/speckle-unreal",
|
||||
"MarketplaceURL": "",
|
||||
"SupportURL": "",
|
||||
"CanContainContent": true,
|
||||
@@ -19,12 +19,21 @@
|
||||
"Name": "SpeckleUnreal",
|
||||
"Type": "Runtime",
|
||||
"LoadingPhase": "Default"
|
||||
},
|
||||
{
|
||||
"Name": "SpeckleUnrealEditor",
|
||||
"Type": "Editor",
|
||||
"LoadingPhase": "PostEngineInit"
|
||||
}
|
||||
],
|
||||
"Plugins": [
|
||||
{
|
||||
"Name": "ProceduralMeshComponent",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "LidarPointCloud",
|
||||
"Enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
|
||||
[/Script/HardwareTargeting.HardwareTargetingSettings]
|
||||
TargetedHardwareClass=Desktop
|
||||
AppliedTargetedHardwareClass=Desktop
|
||||
DefaultGraphicsPerformance=Maximum
|
||||
AppliedDefaultGraphicsPerformance=Maximum
|
||||
|
||||
[/Script/Engine.Engine]
|
||||
+ActiveGameNameRedirects=(OldGameName="TP_Blank",NewGameName="/Script/SpeckleUnrealProject")
|
||||
+ActiveGameNameRedirects=(OldGameName="/Script/TP_Blank",NewGameName="/Script/SpeckleUnrealProject")
|
||||
+ActiveClassRedirects=(OldClassName="TP_BlankGameModeBase",NewClassName="SpeckleUnrealProjectGameModeBase")
|
||||
|
||||
[/Script/IOSRuntimeSettings.IOSRuntimeSettings]
|
||||
RemoteServerName=
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
|
||||
[/Script/EngineSettings.GeneralProjectSettings]
|
||||
ProjectID=F126DB004A50E31B2A69D284041A10E1
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 5.7 KiB |
-256
@@ -1,256 +0,0 @@
|
||||
#include "SpeckleUnrealManager.h"
|
||||
|
||||
// Sets default values
|
||||
ASpeckleUnrealManager::ASpeckleUnrealManager()
|
||||
{
|
||||
//When the object is constructed, Get the HTTP module
|
||||
Http = &FHttpModule::Get();
|
||||
// default conversion is millimeters to centimeters because streams tend to be in ml and unreal is in cm by defaults
|
||||
ScaleFactor = 0.1;
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void ASpeckleUnrealManager::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
World = GetWorld();
|
||||
GetStream();
|
||||
}
|
||||
|
||||
void ASpeckleUnrealManager::SetUpGetRequest(TSharedRef<IHttpRequest> Request)
|
||||
{
|
||||
Request->SetVerb("GET");
|
||||
Request->SetHeader("Content-Type", TEXT("application/json"));
|
||||
Request->SetHeader("Authorization", AuthToken);
|
||||
}
|
||||
|
||||
/*Http call*/
|
||||
void ASpeckleUnrealManager::GetStream()
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, "Downloading: " + StreamID);
|
||||
|
||||
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
|
||||
|
||||
SetUpGetRequest(Request);
|
||||
|
||||
Request->OnProcessRequestComplete().BindUObject(this, &ASpeckleUnrealManager::OnStreamResponseReceived);
|
||||
|
||||
//This is the url on which to process the request
|
||||
Request->SetURL(ServerUrl + "streams/" + StreamID);
|
||||
|
||||
Request->ProcessRequest();
|
||||
}
|
||||
|
||||
/*Assigned function on successfull http call*/
|
||||
void ASpeckleUnrealManager::OnStreamResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
{
|
||||
if (!bWasSuccessful)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Stream Request failed");
|
||||
return;
|
||||
}
|
||||
|
||||
//Create a pointer to hold the json serialized data
|
||||
TSharedPtr<FJsonObject> ResponseJsonObject;
|
||||
|
||||
//Create a reader pointer to read the json data
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
|
||||
|
||||
//Deserialize the json data given Reader and the actual object to deserialize
|
||||
if (FJsonSerializer::Deserialize(Reader, ResponseJsonObject))
|
||||
{
|
||||
//Get the value of the json object by field name
|
||||
FString ResponseMessage = ResponseJsonObject->GetStringField("message");
|
||||
TSharedPtr<FJsonObject> Stream = ResponseJsonObject->GetObjectField("resource");
|
||||
FString StreamName = Stream->GetStringField("name");
|
||||
FString StreamDescription = Stream->GetStringField("description");
|
||||
|
||||
FString Units = ResponseJsonObject->GetObjectField("baseProperties")->GetStringField("units").ToLower();
|
||||
|
||||
// unreal engine units are in cm by default but the conversion is editable by users so
|
||||
// this needs to be accounted for later.
|
||||
if (Units == "meters" || Units == "metres")
|
||||
ScaleFactor = 100;
|
||||
|
||||
if (Units == "centimeters" || Units == "centimetres")
|
||||
ScaleFactor = 1;
|
||||
|
||||
if (Units == "millimeters" || Units == "millimetres")
|
||||
ScaleFactor = 0.1;
|
||||
|
||||
if (Units == "yards")
|
||||
ScaleFactor = 91.4402757;
|
||||
|
||||
if (Units == "feet")
|
||||
ScaleFactor = 30.4799990;
|
||||
|
||||
if (Units == "inches")
|
||||
ScaleFactor = 2.5399986;
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> LayersInStream = Stream->GetArrayField("layers");
|
||||
SpeckleUnrealLayers = TArray<ASpeckleUnrealLayer*>();
|
||||
|
||||
for (size_t i = 0; i < LayersInStream.Num(); i++)
|
||||
{
|
||||
TSharedPtr<FJsonObject> LayerObject = LayersInStream[i]->AsObject();
|
||||
|
||||
FString LayerName = LayerObject->GetStringField("name");
|
||||
int32 StartIndex = LayerObject->GetIntegerField("startIndex");
|
||||
int32 ObjectCount = LayerObject->GetIntegerField("objectCount");
|
||||
|
||||
//USpeckleUnrealLayer NewLayer = USpeckleUnrealLayer(LayerName, StartIndex, ObjectCount);
|
||||
ASpeckleUnrealLayer* NewLayer = (ASpeckleUnrealLayer*)World->SpawnActor(ASpeckleUnrealLayer::StaticClass());
|
||||
NewLayer->Init(LayerName, StartIndex, ObjectCount);
|
||||
SpeckleUnrealLayers.Add(NewLayer);
|
||||
}
|
||||
|
||||
//Output it to the engine
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, "Units: " + FString::SanitizeFloat(ScaleFactor));
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Green, "Status: " + ResponseMessage);
|
||||
GEngine->AddOnScreenDebugMessage(2, 5.0f, FColor::Green, "Name: " + StreamName);
|
||||
GEngine->AddOnScreenDebugMessage(3, 5.0f, FColor::Green, "Description: " + StreamDescription);
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectPlaceholderArray = Stream->GetArrayField("objects");
|
||||
|
||||
GetStreamObjects(ObjectPlaceholderArray.Num());
|
||||
}
|
||||
else
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Couldn't deserialize Json from stream response");
|
||||
GEngine->AddOnScreenDebugMessage(2, 10.0f, FColor::Red, Response->GetContentAsString());
|
||||
}
|
||||
}
|
||||
|
||||
void ASpeckleUnrealManager::GetStreamObjects(int32 objectCount)
|
||||
{
|
||||
int32 RequestLimit = 1;
|
||||
CurrentObjectIndex = 0;
|
||||
LayerIndex = 0;
|
||||
|
||||
for (size_t i = 0; i < objectCount; i += RequestLimit)
|
||||
{
|
||||
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
|
||||
|
||||
SetUpGetRequest(Request);
|
||||
|
||||
Request->OnProcessRequestComplete().BindUObject(this, &ASpeckleUnrealManager::OnStreamObjectResponseReceived);
|
||||
|
||||
//This is the url on which to process the request
|
||||
Request->SetURL(ServerUrl + "streams/" + StreamID + "/objects?limit=" + FString::FromInt(RequestLimit) + "&offset=" + FString::FromInt(i));
|
||||
|
||||
Request->ProcessRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void ASpeckleUnrealManager::OnStreamObjectResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
{
|
||||
if (!bWasSuccessful)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Object Request failed");
|
||||
return;
|
||||
}
|
||||
|
||||
//Create a pointer to hold the json serialized data
|
||||
TSharedPtr<FJsonObject> ResponseJsonObject;
|
||||
|
||||
//Create a reader pointer to read the json data
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
|
||||
|
||||
//Deserialize the json data given Reader and the actual object to deserialize
|
||||
if (FJsonSerializer::Deserialize(Reader, ResponseJsonObject))
|
||||
{
|
||||
|
||||
int32 Offset = FCString::Atoi (*Request->GetURLParameter("offset"));
|
||||
//Get the value of the json object by field name
|
||||
TArray<TSharedPtr<FJsonValue>> StreamObjects = ResponseJsonObject->GetArrayField("resources");
|
||||
|
||||
for (size_t i = 0; i < SpeckleUnrealLayers.Num(); i++)
|
||||
{
|
||||
if (Offset >= SpeckleUnrealLayers[i]->StartIndex)
|
||||
{
|
||||
if (Offset < (SpeckleUnrealLayers[i]->StartIndex + SpeckleUnrealLayers[i]->ObjectCount))
|
||||
LayerIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < StreamObjects.Num(); i++)
|
||||
{
|
||||
TSharedPtr<FJsonObject> StreamObject = StreamObjects[i].Get()->AsObject();
|
||||
|
||||
TSharedPtr<FJsonObject> ObjectToConvert = StreamObject;
|
||||
|
||||
FString objectType = ObjectToConvert->GetStringField("type");
|
||||
|
||||
if (objectType.ToLower().Contains("brep"))
|
||||
{
|
||||
ObjectToConvert = StreamObject->GetObjectField("displayValue");
|
||||
|
||||
objectType = ObjectToConvert->GetStringField("type");
|
||||
}
|
||||
|
||||
if (objectType.ToLower().Contains("mesh"))
|
||||
{
|
||||
AActor* ActorInstance = World->SpawnActor(MeshActor);
|
||||
ASpeckleUnrealMesh* MeshInstance = (ASpeckleUnrealMesh*)ActorInstance;
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectVertices = ObjectToConvert->GetArrayField("vertices");
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectFaces = ObjectToConvert->GetArrayField("faces");
|
||||
|
||||
TArray<FVector> ParsedVerticies;
|
||||
|
||||
for (size_t j = 0; j < ObjectVertices.Num(); j += 3)
|
||||
{
|
||||
ParsedVerticies.Add(FVector
|
||||
(
|
||||
(float)(ObjectVertices[j].Get()->AsNumber()) * -1,
|
||||
(float)(ObjectVertices[j + 1].Get()->AsNumber()),
|
||||
(float)(ObjectVertices[j + 2].Get()->AsNumber())
|
||||
) * ScaleFactor);
|
||||
}
|
||||
|
||||
//convert mesh faces into triangle array regardless of whether or not they are quads
|
||||
TArray<int32> ParsedTriangles;
|
||||
int32 j = 0;
|
||||
while (j < ObjectFaces.Num())
|
||||
{
|
||||
if (ObjectFaces[j].Get()->AsNumber() == 0)
|
||||
{
|
||||
//Triangles
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 2].Get()->AsNumber());
|
||||
j += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Quads to triangles
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 2].Get()->AsNumber());
|
||||
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 4].Get()->AsNumber());
|
||||
|
||||
j += 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (RandomColorsPerLayer)
|
||||
MeshInstance->SetMesh(ParsedVerticies, ParsedTriangles, DefaultMeshMaterial, SpeckleUnrealLayers[LayerIndex]->LayerColor);
|
||||
else
|
||||
MeshInstance->SetMesh(ParsedVerticies, ParsedTriangles, DefaultMeshMaterial, FLinearColor::White);
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("%d"), Offset);
|
||||
UE_LOG(LogTemp, Warning, TEXT("%s"), *SpeckleUnrealLayers[LayerIndex]->LayerName);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Couldn't deserialize Json from object response");
|
||||
GEngine->AddOnScreenDebugMessage(2, 10.0f, FColor::Red, Response->GetContentAsString());
|
||||
}
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "SpeckleUnrealMesh.h"
|
||||
|
||||
// Sets default values
|
||||
ASpeckleUnrealMesh::ASpeckleUnrealMesh()
|
||||
{
|
||||
Scene = CreateDefaultSubobject<USceneComponent>("Root");
|
||||
RootComponent = Scene;
|
||||
|
||||
ProceduralMesh = CreateDefaultSubobject<UProceduralMeshComponent>("Mesh");
|
||||
ProceduralMesh->SetupAttachment(RootComponent);
|
||||
}
|
||||
|
||||
void ASpeckleUnrealMesh::SetMesh(TArray<FVector> Vertices, TArray<int32> Triangles, UMaterialInterface* Material, FLinearColor Color)
|
||||
{
|
||||
ProceduralMesh->ClearAllMeshSections();
|
||||
|
||||
TArray<FVector> Normals;
|
||||
TArray<FProcMeshTangent> Tangents;
|
||||
TArray<FVector2D> UVs;
|
||||
TArray<FColor> Colors;
|
||||
|
||||
// for each triangle
|
||||
for (size_t i = 0; i < Triangles.Num(); i += 3)
|
||||
{
|
||||
// get a normal direction for this triangle
|
||||
FVector Normal = FVector::CrossProduct(Vertices[Triangles[i]], Vertices[Triangles[i + 2]]).GetSafeNormal();
|
||||
|
||||
// get a tangent direction perpendicular to the normal
|
||||
FVector TangentVector = FVector::CrossProduct(Vertices[Triangles[i]], Normal);
|
||||
FProcMeshTangent Tangent = FProcMeshTangent(TangentVector.X, TangentVector.Y, TangentVector.Z);
|
||||
|
||||
// for each vertex in a triangle
|
||||
for (size_t j = 0; j < 3; j++)
|
||||
{
|
||||
Normals.Add(Normal);
|
||||
Tangents.Add(Tangent);
|
||||
Colors.Add(FColor::White);
|
||||
}
|
||||
}
|
||||
|
||||
ProceduralMesh->CreateMeshSection(0, Vertices, Triangles, Normals, UVs, Colors, Tangents, true);
|
||||
|
||||
UMaterialInstanceDynamic* DynMaterial = UMaterialInstanceDynamic::Create(Material, this);
|
||||
|
||||
DynMaterial->SetVectorParameterValue("BaseColor", Color);
|
||||
|
||||
ProceduralMesh->SetMaterial(0, DynMaterial);
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void ASpeckleUnrealMesh::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
}
|
||||
|
||||
// Called every frame
|
||||
void ASpeckleUnrealMesh::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
}
|
||||
|
||||
-304
@@ -1,304 +0,0 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "SpeckleUnrealReceiver.h"
|
||||
|
||||
|
||||
// Sets default values
|
||||
USpeckleUnrealReceiver::USpeckleUnrealReceiver()
|
||||
{
|
||||
//When the object is constructed, Get the HTTP module
|
||||
Http = &FHttpModule::Get();
|
||||
// default conversion is millimeters to centimeters because streams tend to be in ml and unreal is in cm by defaults
|
||||
ScaleFactor = 0.1;
|
||||
}
|
||||
|
||||
void USpeckleUnrealReceiver::SetUpGetRequest(TSharedRef<IHttpRequest> Request)
|
||||
{
|
||||
Request->SetVerb("GET");
|
||||
Request->SetHeader("Content-Type", TEXT("application/json"));
|
||||
Request->SetHeader("Authorization", AuthToken);
|
||||
}
|
||||
|
||||
/*Http call*/
|
||||
void USpeckleUnrealReceiver::ReceiveStream()
|
||||
{
|
||||
World = GetWorld();
|
||||
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, "Downloading: " + StreamID);
|
||||
|
||||
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
|
||||
|
||||
SetUpGetRequest(Request);
|
||||
|
||||
Request->OnProcessRequestComplete().BindUObject(this, &USpeckleUnrealReceiver::OnStreamResponseReceived);
|
||||
|
||||
//This is the url on which to process the request
|
||||
Request->SetURL(ServerUrl + "streams/" + StreamID);
|
||||
|
||||
Request->ProcessRequest();
|
||||
}
|
||||
|
||||
/*Assigned function on successfull http call*/
|
||||
void USpeckleUnrealReceiver::OnStreamResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
{
|
||||
if (!bWasSuccessful)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Stream Request failed");
|
||||
return;
|
||||
}
|
||||
|
||||
//Create a pointer to hold the json serialized data
|
||||
TSharedPtr<FJsonObject> ResponseJsonObject;
|
||||
|
||||
//Create a reader pointer to read the json data
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
|
||||
|
||||
//Deserialize the json data given Reader and the actual object to deserialize
|
||||
if (FJsonSerializer::Deserialize(Reader, ResponseJsonObject))
|
||||
{
|
||||
//Get the value of the json object by field name
|
||||
FString ResponseMessage = ResponseJsonObject->GetStringField("message");
|
||||
TSharedPtr<FJsonObject> Stream = ResponseJsonObject->GetObjectField("resource");
|
||||
FString StreamName = Stream->GetStringField("name");
|
||||
FString StreamDescription = Stream->GetStringField("description");
|
||||
|
||||
FString Units = ResponseJsonObject->GetObjectField("baseProperties")->GetStringField("units").ToLower();
|
||||
|
||||
// unreal engine units are in cm by default but the conversion is editable by users so
|
||||
// this needs to be accounted for later.
|
||||
if (Units == "meters" || Units == "metres")
|
||||
ScaleFactor = 100;
|
||||
|
||||
if (Units == "centimeters" || Units == "centimetres")
|
||||
ScaleFactor = 1;
|
||||
|
||||
if (Units == "millimeters" || Units == "millimetres")
|
||||
ScaleFactor = 0.1;
|
||||
|
||||
if (Units == "yards")
|
||||
ScaleFactor = 91.4402757;
|
||||
|
||||
if (Units == "feet")
|
||||
ScaleFactor = 30.4799990;
|
||||
|
||||
if (Units == "inches")
|
||||
ScaleFactor = 2.5399986;
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> LayersInStream = Stream->GetArrayField("layers");
|
||||
SpeckleUnrealLayers = TArray<ASpeckleUnrealLayer*>();
|
||||
|
||||
for (size_t i = 0; i < LayersInStream.Num(); i++)
|
||||
{
|
||||
TSharedPtr<FJsonObject> LayerObject = LayersInStream[i]->AsObject();
|
||||
|
||||
ASpeckleUnrealLayer* NewLayer = (ASpeckleUnrealLayer*)World->SpawnActor(ASpeckleUnrealLayer::StaticClass());
|
||||
|
||||
FString LayerName = LayerObject->GetStringField("name");
|
||||
|
||||
if (LayerName.Contains("::"))
|
||||
{
|
||||
TArray<FString> Parsed = TArray<FString> ();
|
||||
int32 heirarchySize = LayerName.ParseIntoArray(Parsed, TEXT("::"), true);
|
||||
|
||||
LayerName = Parsed[heirarchySize - 1];
|
||||
FString ParentLayerName = Parsed[heirarchySize - 2];
|
||||
|
||||
for (size_t j = 0; j < SpeckleUnrealLayers.Num(); j++)
|
||||
{
|
||||
if (SpeckleUnrealLayers[j]->LayerName == ParentLayerName)
|
||||
{
|
||||
EAttachmentRule rule = EAttachmentRule();
|
||||
FAttachmentTransformRules rules = FAttachmentTransformRules(rule, false);
|
||||
NewLayer->AttachToActor(SpeckleUnrealLayers[j], rules);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32 StartIndex = LayerObject->GetIntegerField("startIndex");
|
||||
int32 ObjectCount = LayerObject->GetIntegerField("objectCount");
|
||||
|
||||
NewLayer->Init(LayerName, StartIndex, ObjectCount);
|
||||
SpeckleUnrealLayers.Add(NewLayer);
|
||||
}
|
||||
|
||||
//Output it to the engine
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, "Units: " + FString::SanitizeFloat(ScaleFactor));
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Green, "Status: " + ResponseMessage);
|
||||
GEngine->AddOnScreenDebugMessage(2, 5.0f, FColor::Green, "Name: " + StreamName);
|
||||
GEngine->AddOnScreenDebugMessage(3, 5.0f, FColor::Green, "Description: " + StreamDescription);
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectPlaceholderArray = Stream->GetArrayField("objects");
|
||||
|
||||
GetStreamObjects(ObjectPlaceholderArray.Num());
|
||||
}
|
||||
else
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Couldn't deserialize Json from stream response");
|
||||
GEngine->AddOnScreenDebugMessage(2, 10.0f, FColor::Red, Response->GetContentAsString());
|
||||
}
|
||||
}
|
||||
|
||||
void USpeckleUnrealReceiver::GetStreamObjects(int32 objectCount)
|
||||
{
|
||||
ObjectsReceived = TArray<bool>();
|
||||
|
||||
int32 RequestLimit = 1;
|
||||
CurrentObjectIndex = 0;
|
||||
LayerIndex = 0;
|
||||
|
||||
for (size_t i = 0; i < objectCount; i += RequestLimit)
|
||||
{
|
||||
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
|
||||
|
||||
SetUpGetRequest(Request);
|
||||
|
||||
Request->OnProcessRequestComplete().BindUObject(this, &USpeckleUnrealReceiver::OnStreamObjectResponseReceived);
|
||||
|
||||
//This is the url on which to process the request
|
||||
Request->SetURL(ServerUrl + "streams/" + StreamID + "/objects?limit=" + FString::FromInt(RequestLimit) + "&offset=" + FString::FromInt(i));
|
||||
|
||||
ObjectsReceived.Add(false);
|
||||
|
||||
Request->ProcessRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void USpeckleUnrealReceiver::OnStreamObjectResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
{
|
||||
int32 Offset = FCString::Atoi(*Request->GetURLParameter("offset"));
|
||||
|
||||
if (!bWasSuccessful)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Object Request failed");
|
||||
return;
|
||||
}
|
||||
|
||||
//Create a pointer to hold the json serialized data
|
||||
TSharedPtr<FJsonObject> ResponseJsonObject;
|
||||
|
||||
//Create a reader pointer to read the json data
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
|
||||
|
||||
//Deserialize the json data given Reader and the actual object to deserialize
|
||||
if (FJsonSerializer::Deserialize(Reader, ResponseJsonObject))
|
||||
{
|
||||
//Get the value of the json object by field name
|
||||
TArray<TSharedPtr<FJsonValue>> StreamObjects = ResponseJsonObject->GetArrayField("resources");
|
||||
|
||||
for (size_t i = 0; i < SpeckleUnrealLayers.Num(); i++)
|
||||
{
|
||||
if (Offset >= SpeckleUnrealLayers[i]->StartIndex)
|
||||
{
|
||||
if (Offset < (SpeckleUnrealLayers[i]->StartIndex + SpeckleUnrealLayers[i]->ObjectCount))
|
||||
LayerIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < StreamObjects.Num(); i++)
|
||||
{
|
||||
TSharedPtr<FJsonObject> StreamObject = StreamObjects[i].Get()->AsObject();
|
||||
|
||||
TSharedPtr<FJsonObject> ObjectToConvert = StreamObject;
|
||||
|
||||
FString objectType = ObjectToConvert->GetStringField("type");
|
||||
|
||||
if (objectType.ToLower().Contains("brep"))
|
||||
{
|
||||
ObjectToConvert = StreamObject->GetObjectField("displayValue");
|
||||
|
||||
objectType = ObjectToConvert->GetStringField("type");
|
||||
}
|
||||
|
||||
if (objectType.ToLower().Contains("mesh"))
|
||||
{
|
||||
EAttachmentRule rule = EAttachmentRule();
|
||||
FAttachmentTransformRules rules = FAttachmentTransformRules(rule, false);
|
||||
|
||||
ASpeckleUnrealMesh* MeshInstance = World->SpawnActor<ASpeckleUnrealMesh>(ASpeckleUnrealMesh::StaticClass());
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectVertices = ObjectToConvert->GetArrayField("vertices");
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectFaces = ObjectToConvert->GetArrayField("faces");
|
||||
|
||||
TArray<FVector> ParsedVerticies;
|
||||
|
||||
for (size_t j = 0; j < ObjectVertices.Num(); j += 3)
|
||||
{
|
||||
ParsedVerticies.Add(FVector
|
||||
(
|
||||
(float)(ObjectVertices[j].Get()->AsNumber()) * -1,
|
||||
(float)(ObjectVertices[j + 1].Get()->AsNumber()),
|
||||
(float)(ObjectVertices[j + 2].Get()->AsNumber())
|
||||
) * ScaleFactor);
|
||||
}
|
||||
|
||||
//convert mesh faces into triangle array regardless of whether or not they are quads
|
||||
TArray<int32> ParsedTriangles;
|
||||
int32 j = 0;
|
||||
while (j < ObjectFaces.Num())
|
||||
{
|
||||
if (ObjectFaces[j].Get()->AsNumber() == 0)
|
||||
{
|
||||
//Triangles
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 2].Get()->AsNumber());
|
||||
j += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Quads to triangles
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 2].Get()->AsNumber());
|
||||
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 4].Get()->AsNumber());
|
||||
|
||||
j += 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (RandomColorsPerLayer)
|
||||
MeshInstance->SetMesh(ParsedVerticies, ParsedTriangles, DefaultMeshMaterial, SpeckleUnrealLayers[LayerIndex]->LayerColor);
|
||||
else
|
||||
MeshInstance->SetMesh(ParsedVerticies, ParsedTriangles, DefaultMeshMaterial, FLinearColor::White);
|
||||
|
||||
MeshInstance->AttachToActor(SpeckleUnrealLayers[LayerIndex], rules);
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("%d"), Offset);
|
||||
UE_LOG(LogTemp, Warning, TEXT("%s"), *SpeckleUnrealLayers[LayerIndex]->LayerName);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Couldn't deserialize Json from object response");
|
||||
GEngine->AddOnScreenDebugMessage(2, 10.0f, FColor::Red, Response->GetContentAsString());
|
||||
}
|
||||
|
||||
|
||||
ObjectsReceived[Offset] = true;
|
||||
}
|
||||
|
||||
float USpeckleUnrealReceiver::GetStreamProgress()
|
||||
{
|
||||
if (ObjectsReceived.Num() == 0)
|
||||
return 0;
|
||||
|
||||
float ProgressMade = 0;
|
||||
|
||||
for (size_t i = 0; i < ObjectsReceived.Num(); i++)
|
||||
{
|
||||
if (ObjectsReceived[i])
|
||||
ProgressMade++;
|
||||
}
|
||||
|
||||
return ProgressMade / ObjectsReceived.Num();
|
||||
}
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// logs
|
||||
#include "Engine/Engine.h"
|
||||
|
||||
// json manipulation
|
||||
#include "Dom/JsonObject.h"
|
||||
#include "Dom/JsonValue.h"
|
||||
#include "Serialization/JsonReader.h"
|
||||
#include "Serialization/JsonSerializer.h"
|
||||
|
||||
// web requests
|
||||
#include "Runtime/Online/HTTP/Public/Http.h"
|
||||
|
||||
#include "SpeckleUnrealMesh.h"
|
||||
#include "SpeckleUnrealLayer.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "SpeckleUnrealManager.generated.h"
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class SPECKLEUNREAL_API ASpeckleUnrealManager : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
FHttpModule* Http;
|
||||
|
||||
/* The actual HTTP call */
|
||||
UFUNCTION()
|
||||
void GetStream();
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString ServerUrl {
|
||||
"https://hestia.speckle.works/api/"
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString StreamID {
|
||||
""
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString AuthToken {
|
||||
""
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
TSubclassOf<ASpeckleUnrealMesh> MeshActor;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
UMaterialInterface* DefaultMeshMaterial;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
bool RandomColorsPerLayer;
|
||||
|
||||
TArray<ASpeckleUnrealLayer*> SpeckleUnrealLayers;
|
||||
|
||||
/*Assign this function to call when the GET request processes sucessfully*/
|
||||
void OnStreamResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
|
||||
// Sets default values for this actor's properties
|
||||
ASpeckleUnrealManager();
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
protected:
|
||||
|
||||
UWorld* World;
|
||||
|
||||
float ScaleFactor;
|
||||
|
||||
int32 LayerIndex;
|
||||
int32 CurrentObjectIndex;
|
||||
|
||||
void SetUpGetRequest(TSharedRef<IHttpRequest> Request);
|
||||
|
||||
void GetStreamObjects(int32 objectCount);
|
||||
|
||||
void OnStreamObjectResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
};
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
#include "SpeckleUnrealMesh.generated.h"
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class SPECKLEUNREAL_API ASpeckleUnrealMesh : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
USceneComponent* Scene;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
|
||||
UProceduralMeshComponent* ProceduralMesh;
|
||||
|
||||
// Sets default values for this actor's properties
|
||||
ASpeckleUnrealMesh();
|
||||
|
||||
virtual void SetMesh(TArray<FVector> Vertices, TArray<int32> Triangles, UMaterialInterface* Material, FLinearColor Color);
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
};
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
// logs
|
||||
#include "Engine/Engine.h"
|
||||
|
||||
// json manipulation
|
||||
#include "Dom/JsonObject.h"
|
||||
#include "Dom/JsonValue.h"
|
||||
#include "Serialization/JsonReader.h"
|
||||
#include "Serialization/JsonSerializer.h"
|
||||
|
||||
// web requests
|
||||
#include "Runtime/Online/HTTP/Public/Http.h"
|
||||
|
||||
#include "SpeckleUnrealMesh.h"
|
||||
#include "SpeckleUnrealLayer.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/NoExportTypes.h"
|
||||
#include "SpeckleUnrealReceiver.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(BlueprintType)
|
||||
class SPECKLEUNREAL_API USpeckleUnrealReceiver : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
FHttpModule* Http;
|
||||
|
||||
/* The actual HTTP call */
|
||||
UFUNCTION(BlueprintCallable, Category = "Speckle")
|
||||
void ReceiveStream();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Speckle")
|
||||
float GetStreamProgress();
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString ServerUrl {
|
||||
"https://hestia.speckle.works/api/"
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString StreamID {
|
||||
""
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString AuthToken {
|
||||
""
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
TSubclassOf<ASpeckleUnrealMesh> MeshActor;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
UMaterialInterface* DefaultMeshMaterial;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
bool RandomColorsPerLayer;
|
||||
|
||||
TArray<ASpeckleUnrealLayer*> SpeckleUnrealLayers;
|
||||
|
||||
/*Assign this function to call when the GET request processes sucessfully*/
|
||||
void OnStreamResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
|
||||
// Sets default values for this actor's properties
|
||||
USpeckleUnrealReceiver();
|
||||
|
||||
protected:
|
||||
|
||||
UWorld* World;
|
||||
|
||||
float ScaleFactor;
|
||||
|
||||
TArray<bool> ObjectsReceived;
|
||||
|
||||
int32 LayerIndex;
|
||||
int32 CurrentObjectIndex;
|
||||
|
||||
void SetUpGetRequest(TSharedRef<IHttpRequest> Request);
|
||||
|
||||
void GetStreamObjects(int32 objectCount);
|
||||
|
||||
void OnStreamObjectResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
using UnrealBuildTool;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class SpeckleUnrealProjectTarget : TargetRules
|
||||
{
|
||||
public SpeckleUnrealProjectTarget( TargetInfo Target) : base(Target)
|
||||
{
|
||||
Type = TargetType.Game;
|
||||
DefaultBuildSettings = BuildSettingsVersion.V2;
|
||||
ExtraModuleNames.AddRange( new string[] { "SpeckleUnrealProject" } );
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class SpeckleUnrealProject : ModuleRules
|
||||
{
|
||||
public SpeckleUnrealProject(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(new string[] { });
|
||||
|
||||
// Uncomment if you are using Slate UI
|
||||
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
|
||||
|
||||
// Uncomment if you are using online features
|
||||
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||
|
||||
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "SpeckleUnrealProject.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, SpeckleUnrealProject, "SpeckleUnrealProject" );
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
|
||||
#include "SpeckleUnrealProjectGameModeBase.h"
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/GameModeBase.h"
|
||||
#include "SpeckleUnrealProjectGameModeBase.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class SPECKLEUNREALPROJECT_API ASpeckleUnrealProjectGameModeBase : public AGameModeBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
using UnrealBuildTool;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class SpeckleUnrealProjectEditorTarget : TargetRules
|
||||
{
|
||||
public SpeckleUnrealProjectEditorTarget( TargetInfo Target) : base(Target)
|
||||
{
|
||||
Type = TargetType.Editor;
|
||||
DefaultBuildSettings = BuildSettingsVersion.V2;
|
||||
ExtraModuleNames.AddRange( new string[] { "SpeckleUnrealProject" } );
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28315.86
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{94A6C6F3-99B3-346E-9557-ABF9D4064DBD}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Games", "Games", "{8E2F6A87-1826-34F4-940C-CC23A48F9FE4}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UE4", "Intermediate\ProjectFiles\UE4.vcxproj", "{DE17FD13-E94F-4875-9509-F6023C8B5747}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpeckleUnrealProject", "Intermediate\ProjectFiles\SpeckleUnrealProject.vcxproj", "{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Visualizers", "Visualizers", "{1CCEC849-CC72-4C59-8C36-2F7C38706D4C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\..\..\Epic Games\UE_4.25\Engine\Extras\VisualStudioDebugging\UE4.natvis = ..\..\..\Epic Games\UE_4.25\Engine\Extras\VisualStudioDebugging\UE4.natvis
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
DebugGame Editor|Android = DebugGame Editor|Android
|
||||
DebugGame Editor|Win32 = DebugGame Editor|Win32
|
||||
DebugGame Editor|Win64 = DebugGame Editor|Win64
|
||||
DebugGame|Android = DebugGame|Android
|
||||
DebugGame|Win32 = DebugGame|Win32
|
||||
DebugGame|Win64 = DebugGame|Win64
|
||||
Development Editor|Android = Development Editor|Android
|
||||
Development Editor|Win32 = Development Editor|Win32
|
||||
Development Editor|Win64 = Development Editor|Win64
|
||||
Development|Android = Development|Android
|
||||
Development|Win32 = Development|Win32
|
||||
Development|Win64 = Development|Win64
|
||||
Shipping|Android = Shipping|Android
|
||||
Shipping|Win32 = Shipping|Win32
|
||||
Shipping|Win64 = Shipping|Win64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame Editor|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame Editor|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development Editor|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development Editor|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Shipping|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Shipping|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Shipping|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame Editor|Android.ActiveCfg = Invalid|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame Editor|Win32.ActiveCfg = Invalid|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Editor|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame Editor|Win64.Build.0 = DebugGame_Editor|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Android.ActiveCfg = Android_DebugGame|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Android.Build.0 = Android_DebugGame|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Win32.ActiveCfg = DebugGame|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Win32.Build.0 = DebugGame|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Win64.ActiveCfg = DebugGame|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Win64.Build.0 = DebugGame|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development Editor|Android.ActiveCfg = Invalid|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development Editor|Win32.ActiveCfg = Invalid|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development Editor|Win64.ActiveCfg = Development_Editor|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development Editor|Win64.Build.0 = Development_Editor|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Android.ActiveCfg = Android_Development|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Android.Build.0 = Android_Development|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Win32.ActiveCfg = Development|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Win32.Build.0 = Development|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Win64.ActiveCfg = Development|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Win64.Build.0 = Development|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Android.ActiveCfg = Android_Shipping|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Android.Build.0 = Android_Shipping|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Win32.ActiveCfg = Shipping|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Win32.Build.0 = Shipping|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Win64.ActiveCfg = Shipping|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Win64.Build.0 = Shipping|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747} = {94A6C6F3-99B3-346E-9557-ABF9D4064DBD}
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9} = {8E2F6A87-1826-34F4-940C-CC23A48F9FE4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"FileVersion": 3,
|
||||
"EngineAssociation": "4.25",
|
||||
"Category": "",
|
||||
"Description": "",
|
||||
"Modules": [
|
||||
{
|
||||
"Name": "SpeckleUnrealProject",
|
||||
"Type": "Runtime",
|
||||
"LoadingPhase": "Default"
|
||||
}
|
||||
],
|
||||
"TargetPlatforms": [
|
||||
"Android",
|
||||
"AllDesktop",
|
||||
"HoloLens",
|
||||
"LinuxNoEditor",
|
||||
"LinuxAArch64NoEditor",
|
||||
"Lumin",
|
||||
"WindowsNoEditor"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user