Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
VkCV Framework
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Terraform modules
Monitor
Service Desk
Analyze
Contributor analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Vulkan2021
VkCV Framework
Commits
61f60cbb
Commit
61f60cbb
authored
3 years ago
by
Trevor Hollmann
Browse files
Options
Downloads
Patches
Plain Diff
[
#79
] Add URIs to Scene struct.
parent
cd434576
No related branches found
No related tags found
1 merge request
!69
Resolve "Rework Asset Loader API"
Pipeline
#26418
passed
3 years ago
Stage: build
Stage: deploy
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
modules/asset_loader/include/vkcv/asset/asset_loader.hpp
+4
-0
4 additions, 0 deletions
modules/asset_loader/include/vkcv/asset/asset_loader.hpp
modules/asset_loader/src/vkcv/asset/asset_loader.cpp
+53
-10
53 additions, 10 deletions
modules/asset_loader/src/vkcv/asset/asset_loader.cpp
with
57 additions
and
10 deletions
modules/asset_loader/include/vkcv/asset/asset_loader.hpp
+
4
−
0
View file @
61f60cbb
...
@@ -80,6 +80,7 @@ typedef struct {
...
@@ -80,6 +80,7 @@ typedef struct {
* if the image has just RGB or is grayscale.
* if the image has just RGB or is grayscale.
*/
*/
typedef
struct
{
typedef
struct
{
int
uri
;
// index into the URIs array of the Scene
int
sampler
;
// index into the sampler array of the Scene
int
sampler
;
// index into the sampler array of the Scene
uint8_t
channels
;
// number of channels
uint8_t
channels
;
// number of channels
uint16_t
w
,
h
;
// width and height of the texture
uint16_t
w
,
h
;
// width and height of the texture
...
@@ -183,10 +184,12 @@ typedef struct {
...
@@ -183,10 +184,12 @@ typedef struct {
enum
PrimitiveMode
mode
;
// draw as points, lines or triangle?
enum
PrimitiveMode
mode
;
// draw as points, lines or triangle?
size_t
numIndices
,
numVertices
;
size_t
numIndices
,
numVertices
;
struct
{
struct
{
int
uri
;
// index into the URIs array of Scene
enum
IndexType
type
;
// data type of the indices
enum
IndexType
type
;
// data type of the indices
std
::
vector
<
uint8_t
>
data
;
// binary data of the index buffer
std
::
vector
<
uint8_t
>
data
;
// binary data of the index buffer
}
indexBuffer
;
}
indexBuffer
;
struct
{
struct
{
int
uri
;
// index into the URIs array of Scene
std
::
vector
<
uint8_t
>
data
;
// binary data of the vertex buffer
std
::
vector
<
uint8_t
>
data
;
// binary data of the vertex buffer
std
::
vector
<
VertexAttribute
>
attributes
;
// description of one
std
::
vector
<
VertexAttribute
>
attributes
;
// description of one
}
vertexBuffer
;
}
vertexBuffer
;
...
@@ -217,6 +220,7 @@ typedef struct {
...
@@ -217,6 +220,7 @@ typedef struct {
std
::
vector
<
Material
>
materials
;
std
::
vector
<
Material
>
materials
;
std
::
vector
<
Texture
>
textures
;
std
::
vector
<
Texture
>
textures
;
std
::
vector
<
Sampler
>
samplers
;
std
::
vector
<
Sampler
>
samplers
;
std
::
vector
<
std
::
string
>
uris
;
}
Scene
;
}
Scene
;
/**
/**
...
...
This diff is collapsed.
Click to expand it.
modules/asset_loader/src/vkcv/asset/asset_loader.cpp
+
53
−
10
View file @
61f60cbb
...
@@ -92,14 +92,19 @@ int createTextures(const std::vector<fx::gltf::Texture>& tex_src,
...
@@ -92,14 +92,19 @@ int createTextures(const std::vector<fx::gltf::Texture>& tex_src,
const
std
::
vector
<
fx
::
gltf
::
Image
>&
img_src
,
const
std
::
vector
<
fx
::
gltf
::
Image
>&
img_src
,
const
std
::
vector
<
fx
::
gltf
::
Buffer
>&
buf_src
,
const
std
::
vector
<
fx
::
gltf
::
Buffer
>&
buf_src
,
const
std
::
vector
<
fx
::
gltf
::
BufferView
>&
bV_src
,
const
std
::
vector
<
fx
::
gltf
::
BufferView
>&
bV_src
,
const
std
::
string
&
dir
,
std
::
vector
<
Texture
>&
dst
)
const
std
::
string
&
dir
,
std
::
vector
<
std
::
string
>
&
uris
,
std
::
vector
<
Texture
>&
dst
)
{
{
std
::
unordered_map
<
std
::
string
,
int
>
known_uris
;
for
(
int
i
=
0
;
i
<
uris
.
size
();
i
++
)
known_uris
[
uris
[
i
]]
=
i
;
dst
.
clear
();
dst
.
clear
();
dst
.
reserve
(
tex_src
.
size
());
dst
.
reserve
(
tex_src
.
size
());
for
(
const
auto
&
tex
:
tex_src
)
{
for
(
const
auto
&
tex
:
tex_src
)
{
std
::
string
uri
=
dir
+
"/"
+
img_src
[
tex
.
source
].
uri
;
std
::
string
uri
=
dir
+
"/"
+
img_src
[
tex
.
source
].
uri
;
int
w
,
h
,
c
;
int
w
,
h
,
c
;
uint8_t
*
data
;
uint8_t
*
data
;
int
uri_index
=
-
1
;
if
(
!
uri
.
empty
())
{
if
(
!
uri
.
empty
())
{
data
=
stbi_load
(
uri
.
c_str
(),
&
w
,
&
h
,
&
c
,
4
);
data
=
stbi_load
(
uri
.
c_str
(),
&
w
,
&
h
,
&
c
,
4
);
if
(
!
data
)
{
if
(
!
data
)
{
...
@@ -107,8 +112,15 @@ int createTextures(const std::vector<fx::gltf::Texture>& tex_src,
...
@@ -107,8 +112,15 @@ int createTextures(const std::vector<fx::gltf::Texture>& tex_src,
uri
.
c_str
());
uri
.
c_str
());
return
ASSET_ERROR
;
return
ASSET_ERROR
;
}
}
if
(
known_uris
.
count
(
uri
))
{
uri_index
=
known_uris
[
uri
];
}
else
{
uri_index
=
uris
.
size
();
uris
.
push_back
(
uri
);
}
}
else
{
}
else
{
//TODO this is untested. Find gltf file without uri to test it!
// TODO What to do in this case with Texture.uri?
// TODO this is untested. Find gltf file without uri to test it!
const
fx
::
gltf
::
BufferView
bufferView
=
bV_src
[
img_src
[
tex
.
source
].
bufferView
];
const
fx
::
gltf
::
BufferView
bufferView
=
bV_src
[
img_src
[
tex
.
source
].
bufferView
];
data
=
stbi_load_from_memory
(
data
=
stbi_load_from_memory
(
&
buf_src
[
bufferView
.
buffer
].
data
[
bufferView
.
byteOffset
],
&
buf_src
[
bufferView
.
buffer
].
data
[
bufferView
.
byteOffset
],
...
@@ -133,7 +145,9 @@ int createTextures(const std::vector<fx::gltf::Texture>& tex_src,
...
@@ -133,7 +145,9 @@ int createTextures(const std::vector<fx::gltf::Texture>& tex_src,
}
}
free
(
data
);
free
(
data
);
if
(
uri_index
<
0
)
vkcv_log
(
LogLevel
::
WARNING
,
"Texture is missing a URI."
);
dst
.
push_back
({
dst
.
push_back
({
uri_index
,
tex
.
sampler
,
tex
.
sampler
,
static_cast
<
uint8_t
>
(
c
),
static_cast
<
uint8_t
>
(
c
),
static_cast
<
uint16_t
>
(
w
),
static_cast
<
uint16_t
>
(
h
),
static_cast
<
uint16_t
>
(
w
),
static_cast
<
uint16_t
>
(
h
),
...
@@ -383,11 +397,15 @@ int createVertexGroups(fx::gltf::Mesh const& objectMesh,
...
@@ -383,11 +397,15 @@ int createVertexGroups(fx::gltf::Mesh const& objectMesh,
fx
::
gltf
::
Document
&
sceneObjects
,
fx
::
gltf
::
Document
&
sceneObjects
,
std
::
vector
<
VertexGroup
>
&
vertexGroups
,
std
::
vector
<
VertexGroup
>
&
vertexGroups
,
std
::
vector
<
int
>
&
vertexGroupsIndices
,
std
::
vector
<
int
>
&
vertexGroupsIndices
,
std
::
vector
<
std
::
string
>
&
uris
,
int
&
groupCount
,
bool
probe
)
{
int
&
groupCount
,
bool
probe
)
{
const
size_t
numVertexGroups
=
objectMesh
.
primitives
.
size
();
const
size_t
numVertexGroups
=
objectMesh
.
primitives
.
size
();
vertexGroups
.
reserve
(
numVertexGroups
);
vertexGroups
.
reserve
(
numVertexGroups
);
std
::
unordered_map
<
std
::
string
,
int
>
known_uris
;
for
(
int
i
=
0
;
i
<
uris
.
size
();
i
++
)
known_uris
[
uris
[
i
]]
=
i
;
for
(
const
auto
&
objectPrimitive
:
objectMesh
.
primitives
)
{
for
(
const
auto
&
objectPrimitive
:
objectMesh
.
primitives
)
{
std
::
vector
<
VertexAttribute
>
vertexAttributes
;
std
::
vector
<
VertexAttribute
>
vertexAttributes
;
vertexAttributes
.
reserve
(
objectPrimitive
.
attributes
.
size
());
vertexAttributes
.
reserve
(
objectPrimitive
.
attributes
.
size
());
...
@@ -416,9 +434,16 @@ int createVertexGroups(fx::gltf::Mesh const& objectMesh,
...
@@ -416,9 +434,16 @@ int createVertexGroups(fx::gltf::Mesh const& objectMesh,
IndexType
indexType
;
IndexType
indexType
;
std
::
vector
<
uint8_t
>
indexBufferData
=
{};
std
::
vector
<
uint8_t
>
indexBufferData
=
{};
const
fx
::
gltf
::
Accessor
&
indexAccessor
=
sceneObjects
.
accessors
[
objectPrimitive
.
indices
];
const
fx
::
gltf
::
Accessor
&
indexAccessor
=
sceneObjects
.
accessors
[
objectPrimitive
.
indices
];
int
indexBufferURI
;
if
(
objectPrimitive
.
indices
>=
0
&&
!
probe
)
{
// if there is no index buffer, -1 is returned from fx-gltf
if
(
objectPrimitive
.
indices
>=
0
&&
!
probe
)
{
// if there is no index buffer, -1 is returned from fx-gltf
const
fx
::
gltf
::
BufferView
&
indexBufferView
=
sceneObjects
.
bufferViews
[
indexAccessor
.
bufferView
];
const
fx
::
gltf
::
BufferView
&
indexBufferView
=
sceneObjects
.
bufferViews
[
indexAccessor
.
bufferView
];
const
fx
::
gltf
::
Buffer
&
indexBuffer
=
sceneObjects
.
buffers
[
indexBufferView
.
buffer
];
const
fx
::
gltf
::
Buffer
&
indexBuffer
=
sceneObjects
.
buffers
[
indexBufferView
.
buffer
];
if
(
known_uris
.
count
(
indexBuffer
.
uri
))
{
indexBufferURI
=
known_uris
[
indexBuffer
.
uri
];
}
else
{
indexBufferURI
=
uris
.
size
();
uris
.
push_back
(
indexBuffer
.
uri
);
}
indexBufferData
.
resize
(
indexBufferView
.
byteLength
);
indexBufferData
.
resize
(
indexBufferView
.
byteLength
);
{
{
...
@@ -438,6 +463,13 @@ int createVertexGroups(fx::gltf::Mesh const& objectMesh,
...
@@ -438,6 +463,13 @@ int createVertexGroups(fx::gltf::Mesh const& objectMesh,
const
fx
::
gltf
::
BufferView
&
vertexBufferView
=
sceneObjects
.
bufferViews
[
posAccessor
.
bufferView
];
const
fx
::
gltf
::
BufferView
&
vertexBufferView
=
sceneObjects
.
bufferViews
[
posAccessor
.
bufferView
];
const
fx
::
gltf
::
Buffer
&
vertexBuffer
=
sceneObjects
.
buffers
[
vertexBufferView
.
buffer
];
const
fx
::
gltf
::
Buffer
&
vertexBuffer
=
sceneObjects
.
buffers
[
vertexBufferView
.
buffer
];
int
vertexBufferURI
;
if
(
known_uris
.
count
(
vertexBuffer
.
uri
))
{
vertexBufferURI
=
known_uris
[
vertexBuffer
.
uri
];
}
else
{
vertexBufferURI
=
uris
.
size
();
uris
.
push_back
(
vertexBuffer
.
uri
);
}
// only copy relevant part of vertex data
// only copy relevant part of vertex data
uint32_t
relevantBufferOffset
=
std
::
numeric_limits
<
uint32_t
>::
max
();
uint32_t
relevantBufferOffset
=
std
::
numeric_limits
<
uint32_t
>::
max
();
...
@@ -470,8 +502,8 @@ int createVertexGroups(fx::gltf::Mesh const& objectMesh,
...
@@ -470,8 +502,8 @@ int createVertexGroups(fx::gltf::Mesh const& objectMesh,
static_cast
<
PrimitiveMode
>
(
objectPrimitive
.
mode
),
static_cast
<
PrimitiveMode
>
(
objectPrimitive
.
mode
),
sceneObjects
.
accessors
[
objectPrimitive
.
indices
].
count
,
sceneObjects
.
accessors
[
objectPrimitive
.
indices
].
count
,
posAccessor
.
count
,
posAccessor
.
count
,
{
indexType
,
indexBufferData
},
{
indexBufferURI
,
indexType
,
indexBufferData
},
{
vertexBufferData
,
vertexAttributes
},
{
vertexBufferURI
,
vertexBufferData
,
vertexAttributes
},
{
posAccessor
.
min
[
0
],
posAccessor
.
min
[
1
],
posAccessor
.
min
[
2
]},
{
posAccessor
.
min
[
0
],
posAccessor
.
min
[
1
],
posAccessor
.
min
[
2
]},
{
posAccessor
.
max
[
0
],
posAccessor
.
max
[
1
],
posAccessor
.
max
[
2
]},
{
posAccessor
.
max
[
0
],
posAccessor
.
max
[
1
],
posAccessor
.
max
[
2
]},
static_cast
<
uint8_t
>
(
objectPrimitive
.
material
)
static_cast
<
uint8_t
>
(
objectPrimitive
.
material
)
...
@@ -573,13 +605,16 @@ int loadScene(const std::filesystem::path &path, Scene &scene){
...
@@ -573,13 +605,16 @@ int loadScene(const std::filesystem::path &path, Scene &scene){
std
::
vector
<
Sampler
>
samplers
;
std
::
vector
<
Sampler
>
samplers
;
std
::
vector
<
Mesh
>
meshes
;
std
::
vector
<
Mesh
>
meshes
;
std
::
vector
<
VertexGroup
>
vertexGroups
;
std
::
vector
<
VertexGroup
>
vertexGroups
;
std
::
vector
<
std
::
string
>
uris
;
int
groupCount
=
0
;
int
groupCount
=
0
;
for
(
size_t
i
=
0
;
i
<
sceneObjects
.
meshes
.
size
();
i
++
){
for
(
size_t
i
=
0
;
i
<
sceneObjects
.
meshes
.
size
();
i
++
){
std
::
vector
<
int
>
vertexGroupsIndices
;
std
::
vector
<
int
>
vertexGroupsIndices
;
fx
::
gltf
::
Mesh
const
&
objectMesh
=
sceneObjects
.
meshes
[
i
];
fx
::
gltf
::
Mesh
const
&
objectMesh
=
sceneObjects
.
meshes
[
i
];
if
(
createVertexGroups
(
objectMesh
,
sceneObjects
,
vertexGroups
,
vertexGroupsIndices
,
groupCount
,
false
)
!=
ASSET_SUCCESS
)
{
if
(
createVertexGroups
(
objectMesh
,
sceneObjects
,
vertexGroups
,
vertexGroupsIndices
,
uris
,
groupCount
,
false
)
!=
ASSET_SUCCESS
)
{
vkcv_log
(
LogLevel
::
ERROR
,
"Failed to get Vertex Groups!"
);
vkcv_log
(
LogLevel
::
ERROR
,
"Failed to get Vertex Groups!"
);
return
ASSET_ERROR
;
return
ASSET_ERROR
;
}
}
...
@@ -603,7 +638,7 @@ int loadScene(const std::filesystem::path &path, Scene &scene){
...
@@ -603,7 +638,7 @@ int loadScene(const std::filesystem::path &path, Scene &scene){
}
}
}
}
if
(
createTextures
(
sceneObjects
.
textures
,
sceneObjects
.
images
,
sceneObjects
.
buffers
,
sceneObjects
.
bufferViews
,
dir
,
textures
)
!=
ASSET_SUCCESS
)
{
if
(
createTextures
(
sceneObjects
.
textures
,
sceneObjects
.
images
,
sceneObjects
.
buffers
,
sceneObjects
.
bufferViews
,
dir
,
uris
,
textures
)
!=
ASSET_SUCCESS
)
{
size_t
missing
=
sceneObjects
.
textures
.
size
()
-
textures
.
size
();
size_t
missing
=
sceneObjects
.
textures
.
size
()
-
textures
.
size
();
vkcv_log
(
LogLevel
::
ERROR
,
"Failed to get %lu textures from glTF source '%s'"
,
vkcv_log
(
LogLevel
::
ERROR
,
"Failed to get %lu textures from glTF source '%s'"
,
missing
,
path
.
c_str
());
missing
,
path
.
c_str
());
...
@@ -685,6 +720,7 @@ int probeScene(const std::filesystem::path& path, Scene& scene) {
...
@@ -685,6 +720,7 @@ int probeScene(const std::filesystem::path& path, Scene& scene) {
std
::
vector
<
Sampler
>
samplers
;
std
::
vector
<
Sampler
>
samplers
;
std
::
vector
<
Mesh
>
meshes
;
std
::
vector
<
Mesh
>
meshes
;
std
::
vector
<
VertexGroup
>
vertexGroups
;
std
::
vector
<
VertexGroup
>
vertexGroups
;
std
::
vector
<
std
::
string
>
uris
;
int
groupCount
=
0
;
int
groupCount
=
0
;
std
::
set
<
std
::
string
>
names
;
std
::
set
<
std
::
string
>
names
;
...
@@ -692,7 +728,9 @@ int probeScene(const std::filesystem::path& path, Scene& scene) {
...
@@ -692,7 +728,9 @@ int probeScene(const std::filesystem::path& path, Scene& scene) {
std
::
vector
<
int
>
vertexGroupsIndices
;
std
::
vector
<
int
>
vertexGroupsIndices
;
fx
::
gltf
::
Mesh
const
&
objectMesh
=
sceneObjects
.
meshes
[
i
];
fx
::
gltf
::
Mesh
const
&
objectMesh
=
sceneObjects
.
meshes
[
i
];
if
(
createVertexGroups
(
objectMesh
,
sceneObjects
,
vertexGroups
,
vertexGroupsIndices
,
groupCount
,
true
)
!=
ASSET_SUCCESS
)
{
if
(
createVertexGroups
(
objectMesh
,
sceneObjects
,
vertexGroups
,
vertexGroupsIndices
,
uris
,
groupCount
,
true
)
!=
ASSET_SUCCESS
)
{
vkcv_log
(
LogLevel
::
ERROR
,
"Failed to get Vertex Groups!"
);
vkcv_log
(
LogLevel
::
ERROR
,
"Failed to get Vertex Groups!"
);
return
ASSET_ERROR
;
return
ASSET_ERROR
;
}
}
...
@@ -722,7 +760,7 @@ int probeScene(const std::filesystem::path& path, Scene& scene) {
...
@@ -722,7 +760,7 @@ int probeScene(const std::filesystem::path& path, Scene& scene) {
}
}
}
}
/*if (createTextures(sceneObjects.textures, sceneObjects.images, sceneObjects.buffers, sceneObjects.bufferViews, dir, textures) != ASSET_SUCCESS) {
/*if (createTextures(sceneObjects.textures, sceneObjects.images, sceneObjects.buffers, sceneObjects.bufferViews, dir,
uris,
textures) != ASSET_SUCCESS) {
size_t missing = sceneObjects.textures.size() - textures.size();
size_t missing = sceneObjects.textures.size() - textures.size();
vkcv_log(LogLevel::ERROR, "Failed to get %lu textures from glTF source '%s'",
vkcv_log(LogLevel::ERROR, "Failed to get %lu textures from glTF source '%s'",
missing, path.c_str());
missing, path.c_str());
...
@@ -786,6 +824,7 @@ int loadMesh(const std::filesystem::path &path, const std::string &name, Scene &
...
@@ -786,6 +824,7 @@ int loadMesh(const std::filesystem::path &path, const std::string &name, Scene &
std
::
vector
<
Sampler
>
samplers
;
std
::
vector
<
Sampler
>
samplers
;
std
::
vector
<
Mesh
>
meshes
;
std
::
vector
<
Mesh
>
meshes
;
std
::
vector
<
VertexGroup
>
vertexGroups
;
std
::
vector
<
VertexGroup
>
vertexGroups
;
std
::
vector
<
std
::
string
>
uris
;
int
groupCount
=
0
;
int
groupCount
=
0
;
int
meshIndex
=
-
1
;
int
meshIndex
=
-
1
;
...
@@ -794,7 +833,11 @@ int loadMesh(const std::filesystem::path &path, const std::string &name, Scene &
...
@@ -794,7 +833,11 @@ int loadMesh(const std::filesystem::path &path, const std::string &name, Scene &
std
::
vector
<
int
>
vertexGroupsIndices
;
std
::
vector
<
int
>
vertexGroupsIndices
;
fx
::
gltf
::
Mesh
const
&
objectMesh
=
sceneObjects
.
meshes
[
i
];
fx
::
gltf
::
Mesh
const
&
objectMesh
=
sceneObjects
.
meshes
[
i
];
if
(
createVertexGroups
(
objectMesh
,
sceneObjects
,
vertexGroups
,
vertexGroupsIndices
,
groupCount
,
false
)
!=
ASSET_SUCCESS
)
{
if
(
createVertexGroups
(
objectMesh
,
sceneObjects
,
vertexGroups
,
vertexGroupsIndices
,
uris
,
groupCount
,
false
)
!=
ASSET_SUCCESS
)
{
vkcv_log
(
LogLevel
::
ERROR
,
"Failed to get Vertex Groups!"
);
vkcv_log
(
LogLevel
::
ERROR
,
"Failed to get Vertex Groups!"
);
return
ASSET_ERROR
;
return
ASSET_ERROR
;
}
}
...
@@ -824,7 +867,7 @@ int loadMesh(const std::filesystem::path &path, const std::string &name, Scene &
...
@@ -824,7 +867,7 @@ int loadMesh(const std::filesystem::path &path, const std::string &name, Scene &
);
);
}
}
if
(
createTextures
(
sceneObjects
.
textures
,
sceneObjects
.
images
,
sceneObjects
.
buffers
,
sceneObjects
.
bufferViews
,
dir
,
textures
)
!=
ASSET_SUCCESS
)
{
if
(
createTextures
(
sceneObjects
.
textures
,
sceneObjects
.
images
,
sceneObjects
.
buffers
,
sceneObjects
.
bufferViews
,
dir
,
uris
,
textures
)
!=
ASSET_SUCCESS
)
{
size_t
missing
=
sceneObjects
.
textures
.
size
()
-
textures
.
size
();
size_t
missing
=
sceneObjects
.
textures
.
size
()
-
textures
.
size
();
vkcv_log
(
LogLevel
::
ERROR
,
"Failed to get %lu textures from glTF source '%s'"
,
vkcv_log
(
LogLevel
::
ERROR
,
"Failed to get %lu textures from glTF source '%s'"
,
missing
,
path
.
c_str
());
missing
,
path
.
c_str
());
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment