mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 08:04:01 +02:00
Merge pull request #3342 from ey6es/metavoxels
Very basic beginnings of an implementation of the dual contour algorithm, including necessary data representation and tools.
This commit is contained in:
commit
886add11db
26 changed files with 3339 additions and 1016 deletions
26
interface/resources/shaders/directional_light.frag
Normal file
26
interface/resources/shaders/directional_light.frag
Normal file
|
@ -0,0 +1,26 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// directional_light.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/3/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
void main(void) {
|
||||
// compute the base color based on OpenGL lighting model
|
||||
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
|
||||
gl_FragColor = vec4((texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor +
|
||||
gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * max(0.0, dot(normal * 2.0 -
|
||||
vec4(1.0, 1.0, 1.0, 2.0), gl_LightSource[0].position)))).rgb, normal.a);
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heightfield.frag
|
||||
// directional_light.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 7/28/14.
|
||||
// Created by Andrzej Kapolka on 9/3/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -14,6 +14,12 @@
|
|||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
|
@ -21,28 +27,39 @@ uniform sampler2DShadow shadowMap;
|
|||
uniform vec3 shadowDistances;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
uniform float shadowScale;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
// the distance to the near clip plane
|
||||
uniform float near;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
// scale factor for depth: (far - near) / far
|
||||
uniform float depthScale;
|
||||
|
||||
// offset for depth texture coordinates
|
||||
uniform vec2 depthTexCoordOffset;
|
||||
|
||||
// scale for depth texture coordinates
|
||||
uniform vec2 depthTexCoordScale;
|
||||
|
||||
void main(void) {
|
||||
// compute the view space position using the depth
|
||||
float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0);
|
||||
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0);
|
||||
|
||||
// compute the index of the cascade to use and the corresponding texture coordinates
|
||||
int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
||||
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
|
||||
dot(gl_EyePlaneR[shadowIndex], position));
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
float diffuse = dot(normalize(normal), gl_LightSource[0].position);
|
||||
// compute the color based on OpenGL lighting model, use the alpha from the normal map
|
||||
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
|
||||
float diffuse = dot(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0), gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor +
|
||||
gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
gl_FragColor = vec4(baseColor.rgb, normal.a);
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// directional_light.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/3/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
uniform float shadowScale;
|
||||
|
||||
// the distance to the near clip plane
|
||||
uniform float near;
|
||||
|
||||
// scale factor for depth: (far - near) / far
|
||||
uniform float depthScale;
|
||||
|
||||
// offset for depth texture coordinates
|
||||
uniform vec2 depthTexCoordOffset;
|
||||
|
||||
// scale for depth texture coordinates
|
||||
uniform vec2 depthTexCoordScale;
|
||||
|
||||
void main(void) {
|
||||
// compute the view space position using the depth
|
||||
float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0);
|
||||
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0);
|
||||
|
||||
// compute the corresponding texture coordinates
|
||||
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position));
|
||||
|
||||
// compute the color based on OpenGL lighting model, use the alpha from the normal map
|
||||
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
|
||||
float diffuse = dot(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0), gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor +
|
||||
gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
gl_FragColor = vec4(baseColor.rgb, normal.a);
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heightfield.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 7/28/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// compute the base color based on OpenGL lighting model
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalize(normal), gl_LightSource[0].position)));
|
||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heighfield.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 7/28/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the height texture
|
||||
uniform sampler2D heightMap;
|
||||
|
||||
// the distance between height points in texture space
|
||||
uniform float heightScale;
|
||||
|
||||
// the scale between height and color textures
|
||||
uniform float colorScale;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// transform and store the normal for interpolation
|
||||
vec2 heightCoord = gl_MultiTexCoord0.st;
|
||||
float deltaX = texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r -
|
||||
texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r;
|
||||
float deltaZ = texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r -
|
||||
texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r;
|
||||
normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0));
|
||||
|
||||
// add the height to the position
|
||||
float height = texture2D(heightMap, heightCoord).r;
|
||||
position = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));
|
||||
gl_Position = gl_ProjectionMatrix * position;
|
||||
|
||||
// the zero height should be invisible
|
||||
gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0));
|
||||
|
||||
// pass along the scaled/offset texture coordinates
|
||||
gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale;
|
||||
|
||||
// and the shadow texture coordinates
|
||||
gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0);
|
||||
}
|
|
@ -14,7 +14,11 @@
|
|||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// compute the base color based on OpenGL lighting model
|
||||
gl_FragColor = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
gl_FragData[0] = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
}
|
||||
|
|
|
@ -20,9 +20,20 @@ uniform float heightScale;
|
|||
// the scale between height and color textures
|
||||
uniform float colorScale;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// transform and store the normal for interpolation
|
||||
vec2 heightCoord = gl_MultiTexCoord0.st;
|
||||
float deltaX = texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r -
|
||||
texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r;
|
||||
float deltaZ = texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r -
|
||||
texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r;
|
||||
normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0));
|
||||
|
||||
// add the height to the position
|
||||
float height = texture2D(heightMap, gl_MultiTexCoord0.st).r;
|
||||
float height = texture2D(heightMap, heightCoord).r;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));
|
||||
|
||||
// the zero height should be invisible
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heightfield_light.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 8/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// compute the base color based on OpenGL lighting model
|
||||
gl_FragColor = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalize(normal), gl_LightSource[0].position)));
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heighfield_light.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 8/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the height texture
|
||||
uniform sampler2D heightMap;
|
||||
|
||||
// the distance between height points in texture space
|
||||
uniform float heightScale;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// transform and store the normal for interpolation
|
||||
vec2 heightCoord = gl_MultiTexCoord0.st;
|
||||
float deltaX = texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r -
|
||||
texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r;
|
||||
float deltaZ = texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r -
|
||||
texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r;
|
||||
normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0));
|
||||
|
||||
// add the height to the position
|
||||
float height = texture2D(heightMap, heightCoord).r;
|
||||
position = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));
|
||||
gl_Position = gl_ProjectionMatrix * position;
|
||||
|
||||
// the zero height should be invisible
|
||||
gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0));
|
||||
|
||||
// and the shadow texture coordinates
|
||||
gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0);
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heightfield_light_cascaded_shadow_map.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 8/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the distances to the cascade sections
|
||||
uniform vec3 shadowDistances;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// compute the index of the cascade to use and the corresponding texture coordinates
|
||||
int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
||||
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
|
||||
dot(gl_EyePlaneR[shadowIndex], position));
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
float diffuse = dot(normalize(normal), gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
gl_FragColor = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heightfield_light_shadow_map.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 8/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// compute the base color based on OpenGL lighting model
|
||||
float diffuse = dot(normalize(normal), gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
gl_FragColor = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heightfield.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 7/28/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// compute the base color based on OpenGL lighting model
|
||||
float diffuse = dot(normalize(normal), gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
}
|
21
interface/resources/shaders/metavoxel_voxel_base.frag
Normal file
21
interface/resources/shaders/metavoxel_voxel_base.frag
Normal file
|
@ -0,0 +1,21 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_voxel_base.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/4/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// store the interpolated color and normal
|
||||
gl_FragData[0] = gl_Color;
|
||||
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
}
|
26
interface/resources/shaders/metavoxel_voxel_base.vert
Normal file
26
interface/resources/shaders/metavoxel_voxel_base.vert
Normal file
|
@ -0,0 +1,26 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_voxel_base.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/4/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// transform and store the normal for interpolation
|
||||
normal = vec4(normalize(gl_NormalMatrix * gl_Normal), 0.0);
|
||||
|
||||
// use the fixed-function position
|
||||
gl_Position = ftransform();
|
||||
|
||||
// copy the color for interpolation
|
||||
gl_FrontColor = vec4(gl_Color.rgb, 0.0);
|
||||
}
|
29
interface/resources/shaders/metavoxel_voxel_splat.frag
Normal file
29
interface/resources/shaders/metavoxel_voxel_splat.frag
Normal file
|
@ -0,0 +1,29 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_voxel_splat.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/4/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the number of splats per pass
|
||||
const int SPLAT_COUNT = 4;
|
||||
|
||||
// the splat textures
|
||||
uniform sampler2D diffuseMaps[SPLAT_COUNT];
|
||||
|
||||
// alpha values for the four splat textures
|
||||
varying vec4 alphaValues;
|
||||
|
||||
void main(void) {
|
||||
// blend the splat textures
|
||||
gl_FragColor = (texture2D(diffuseMaps[0], gl_TexCoord[0].st) * alphaValues.x +
|
||||
texture2D(diffuseMaps[1], gl_TexCoord[1].st) * alphaValues.y +
|
||||
texture2D(diffuseMaps[2], gl_TexCoord[2].st) * alphaValues.z +
|
||||
texture2D(diffuseMaps[3], gl_TexCoord[3].st) * alphaValues.w);
|
||||
}
|
62
interface/resources/shaders/metavoxel_voxel_splat.vert
Normal file
62
interface/resources/shaders/metavoxel_voxel_splat.vert
Normal file
|
@ -0,0 +1,62 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_voxel_splat.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/4/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the splat textures scales on the S axis
|
||||
uniform vec4 splatTextureScalesS;
|
||||
|
||||
// the splat texture scales on the T axis
|
||||
uniform vec4 splatTextureScalesT;
|
||||
|
||||
// the lower bounds of the values corresponding to the splat textures
|
||||
uniform vec4 textureValueMinima;
|
||||
|
||||
// the upper bounds of the values corresponding to the splat textures
|
||||
uniform vec4 textureValueMaxima;
|
||||
|
||||
// the materials to apply to the vertex
|
||||
attribute vec4 materials;
|
||||
|
||||
// the weights of each material
|
||||
attribute vec4 materialWeights;
|
||||
|
||||
// alpha values for the four splat textures
|
||||
varying vec4 alphaValues;
|
||||
|
||||
void main(void) {
|
||||
// use the fixed-function position
|
||||
gl_Position = ftransform();
|
||||
|
||||
// pass along the scaled/offset texture coordinates
|
||||
vec4 textureSpacePosition = vec4(gl_Vertex.xz, 0.0, 1.0);
|
||||
gl_TexCoord[0] = textureSpacePosition * vec4(splatTextureScalesS[0], splatTextureScalesT[0], 0.0, 1.0);
|
||||
gl_TexCoord[1] = textureSpacePosition * vec4(splatTextureScalesS[1], splatTextureScalesT[1], 0.0, 1.0);
|
||||
gl_TexCoord[2] = textureSpacePosition * vec4(splatTextureScalesS[2], splatTextureScalesT[2], 0.0, 1.0);
|
||||
gl_TexCoord[3] = textureSpacePosition * vec4(splatTextureScalesS[3], splatTextureScalesT[3], 0.0, 1.0);
|
||||
|
||||
// compute the alpha values for each texture
|
||||
float value = materials[0];
|
||||
vec4 valueVector = vec4(value, value, value, value);
|
||||
alphaValues = step(textureValueMinima, valueVector) * step(valueVector, textureValueMaxima) * materialWeights[0];
|
||||
|
||||
value = materials[1];
|
||||
valueVector = vec4(value, value, value, value);
|
||||
alphaValues += step(textureValueMinima, valueVector) * step(valueVector, textureValueMaxima) * materialWeights[1];
|
||||
|
||||
value = materials[2];
|
||||
valueVector = vec4(value, value, value, value);
|
||||
alphaValues += step(textureValueMinima, valueVector) * step(valueVector, textureValueMaxima) * materialWeights[2];
|
||||
|
||||
value = materials[3];
|
||||
valueVector = vec4(value, value, value, value);
|
||||
alphaValues += step(textureValueMinima, valueVector) * step(valueVector, textureValueMaxima) * materialWeights[3];
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -39,6 +39,7 @@ public:
|
|||
|
||||
const AttributePointer& getPointBufferAttribute() { return _pointBufferAttribute; }
|
||||
const AttributePointer& getHeightfieldBufferAttribute() { return _heightfieldBufferAttribute; }
|
||||
const AttributePointer& getVoxelBufferAttribute() { return _voxelBufferAttribute; }
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
@ -51,6 +52,12 @@ public:
|
|||
|
||||
Q_INVOKABLE void deleteTextures(int heightID, int colorID, int textureID);
|
||||
|
||||
void noteNeedToLight() { _needToLight = true; }
|
||||
|
||||
signals:
|
||||
|
||||
void rendering();
|
||||
|
||||
protected:
|
||||
|
||||
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
|
||||
|
@ -59,12 +66,33 @@ private:
|
|||
|
||||
void guideToAugmented(MetavoxelVisitor& visitor, bool render = false);
|
||||
|
||||
class LightLocations {
|
||||
public:
|
||||
int shadowDistances;
|
||||
int shadowScale;
|
||||
int nearLocation;
|
||||
int depthScale;
|
||||
int depthTexCoordOffset;
|
||||
int depthTexCoordScale;
|
||||
};
|
||||
|
||||
static void loadLightProgram(const char* name, ProgramObject& program, LightLocations& locations);
|
||||
|
||||
AttributePointer _pointBufferAttribute;
|
||||
AttributePointer _heightfieldBufferAttribute;
|
||||
AttributePointer _voxelBufferAttribute;
|
||||
|
||||
MetavoxelLOD _lod;
|
||||
QReadWriteLock _lodLock;
|
||||
Frustum _frustum;
|
||||
bool _needToLight;
|
||||
|
||||
ProgramObject _directionalLight;
|
||||
LightLocations _directionalLightLocations;
|
||||
ProgramObject _directionalLightShadowMap;
|
||||
LightLocations _directionalLightShadowMapLocations;
|
||||
ProgramObject _directionalLightCascadedShadowMap;
|
||||
LightLocations _directionalLightCascadedShadowMapLocations;
|
||||
};
|
||||
|
||||
/// Describes contents of a point in a point buffer.
|
||||
|
@ -143,8 +171,8 @@ public:
|
|||
static const int HEIGHT_EXTENSION;
|
||||
|
||||
HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height,
|
||||
const QByteArray& color, const QByteArray& texture = QByteArray(),
|
||||
const QVector<SharedObjectPointer>& textures = QVector<SharedObjectPointer>());
|
||||
const QByteArray& color, const QByteArray& material = QByteArray(),
|
||||
const QVector<SharedObjectPointer>& materials = QVector<SharedObjectPointer>());
|
||||
~HeightfieldBuffer();
|
||||
|
||||
const glm::vec3& getTranslation() const { return _translation; }
|
||||
|
@ -159,10 +187,10 @@ public:
|
|||
QByteArray& getColor() { return _color; }
|
||||
const QByteArray& getColor() const { return _color; }
|
||||
|
||||
QByteArray& getTexture() { return _texture; }
|
||||
const QByteArray& getTexture() const { return _texture; }
|
||||
QByteArray& getMaterial() { return _material; }
|
||||
const QByteArray& getMaterial() const { return _material; }
|
||||
|
||||
const QVector<SharedObjectPointer>& getTextures() const { return _textures; }
|
||||
const QVector<SharedObjectPointer>& getMaterials() const { return _materials; }
|
||||
|
||||
QByteArray getUnextendedHeight() const;
|
||||
QByteArray getUnextendedColor() const;
|
||||
|
@ -183,11 +211,11 @@ private:
|
|||
Box _colorBounds;
|
||||
QByteArray _height;
|
||||
QByteArray _color;
|
||||
QByteArray _texture;
|
||||
QVector<SharedObjectPointer> _textures;
|
||||
QByteArray _material;
|
||||
QVector<SharedObjectPointer> _materials;
|
||||
GLuint _heightTextureID;
|
||||
GLuint _colorTextureID;
|
||||
GLuint _textureTextureID;
|
||||
GLuint _materialTextureID;
|
||||
QVector<NetworkTexturePointer> _networkTextures;
|
||||
int _heightSize;
|
||||
float _heightIncrement;
|
||||
|
@ -212,6 +240,37 @@ private:
|
|||
QVector<BufferDataPointer> _buffers;
|
||||
};
|
||||
|
||||
/// Describes contents of a vertex in a voxel buffer.
|
||||
class VoxelPoint {
|
||||
public:
|
||||
glm::vec3 vertex;
|
||||
quint8 color[3];
|
||||
char normal[3];
|
||||
quint8 materials[4];
|
||||
quint8 materialWeights[4];
|
||||
};
|
||||
|
||||
/// Contains the information necessary to render a voxel block.
|
||||
class VoxelBuffer : public BufferData {
|
||||
public:
|
||||
|
||||
VoxelBuffer(const QVector<VoxelPoint>& vertices, const QVector<int>& indices,
|
||||
const QVector<SharedObjectPointer>& materials = QVector<SharedObjectPointer>());
|
||||
|
||||
virtual void render(bool cursor = false);
|
||||
|
||||
private:
|
||||
|
||||
QVector<VoxelPoint> _vertices;
|
||||
QVector<int> _indices;
|
||||
int _vertexCount;
|
||||
int _indexCount;
|
||||
QOpenGLBuffer _vertexBuffer;
|
||||
QOpenGLBuffer _indexBuffer;
|
||||
QVector<SharedObjectPointer> _materials;
|
||||
QVector<NetworkTexturePointer> _networkTextures;
|
||||
};
|
||||
|
||||
/// A client-side attribute that stores renderable buffers.
|
||||
class BufferDataAttribute : public InlineAttribute<BufferDataPointer> {
|
||||
Q_OBJECT
|
||||
|
@ -233,42 +292,33 @@ public:
|
|||
|
||||
static void init();
|
||||
|
||||
static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; }
|
||||
static int getHeightScaleLocation() { return _heightScaleLocation; }
|
||||
static int getColorScaleLocation() { return _colorScaleLocation; }
|
||||
|
||||
static ProgramObject& getShadowMapHeightfieldProgram() { return _shadowMapHeightfieldProgram; }
|
||||
static int getShadowMapHeightScaleLocation() { return _shadowMapHeightScaleLocation; }
|
||||
static int getShadowMapColorScaleLocation() { return _shadowMapColorScaleLocation; }
|
||||
|
||||
static ProgramObject& getCascadedShadowMapHeightfieldProgram() { return _cascadedShadowMapHeightfieldProgram; }
|
||||
static int getCascadedShadowMapHeightScaleLocation() { return _cascadedShadowMapHeightScaleLocation; }
|
||||
static int getCascadedShadowMapColorScaleLocation() { return _cascadedShadowMapColorScaleLocation; }
|
||||
|
||||
static ProgramObject& getBaseHeightfieldProgram() { return _baseHeightfieldProgram; }
|
||||
static int getBaseHeightScaleLocation() { return _baseHeightScaleLocation; }
|
||||
static int getBaseColorScaleLocation() { return _baseColorScaleLocation; }
|
||||
|
||||
class SplatLocations {
|
||||
public:
|
||||
int heightScale;
|
||||
int textureScale;
|
||||
int splatTextureOffset;
|
||||
int splatTextureScalesS;
|
||||
int splatTextureScalesT;
|
||||
int textureValueMinima;
|
||||
int textureValueMaxima;
|
||||
int materials;
|
||||
int materialWeights;
|
||||
};
|
||||
|
||||
static ProgramObject& getSplatHeightfieldProgram() { return _splatHeightfieldProgram; }
|
||||
static int getSplatHeightScaleLocation() { return _splatHeightScaleLocation; }
|
||||
static int getSplatTextureScaleLocation() { return _splatTextureScaleLocation; }
|
||||
static int getSplatTextureOffsetLocation() { return _splatTextureOffsetLocation; }
|
||||
static int getSplatTextureScalesSLocation() { return _splatTextureScalesSLocation; }
|
||||
static int getSplatTextureScalesTLocation() { return _splatTextureScalesTLocation; }
|
||||
static int getSplatTextureValueMinimaLocation() { return _splatTextureValueMinimaLocation; }
|
||||
static int getSplatTextureValueMaximaLocation() { return _splatTextureValueMaximaLocation; }
|
||||
|
||||
static ProgramObject& getLightHeightfieldProgram() { return _lightHeightfieldProgram; }
|
||||
static int getLightHeightScaleLocation() { return _lightHeightScaleLocation; }
|
||||
|
||||
static ProgramObject& getShadowLightHeightfieldProgram() { return _shadowLightHeightfieldProgram; }
|
||||
static int getShadowLightHeightScaleLocation() { return _shadowLightHeightScaleLocation; }
|
||||
|
||||
static ProgramObject& getCascadedShadowLightHeightfieldProgram() { return _cascadedShadowLightHeightfieldProgram; }
|
||||
static int getCascadedShadowLightHeightScaleLocation() { return _cascadedShadowLightHeightScaleLocation; }
|
||||
static const SplatLocations& getSplatHeightfieldLocations() { return _splatHeightfieldLocations; }
|
||||
|
||||
static ProgramObject& getHeightfieldCursorProgram() { return _heightfieldCursorProgram; }
|
||||
|
||||
static ProgramObject& getBaseVoxelProgram() { return _baseVoxelProgram; }
|
||||
|
||||
static ProgramObject& getSplatVoxelProgram() { return _splatVoxelProgram; }
|
||||
static const SplatLocations& getSplatVoxelLocations() { return _splatVoxelLocations; }
|
||||
|
||||
Q_INVOKABLE DefaultMetavoxelRendererImplementation();
|
||||
|
||||
virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod);
|
||||
|
@ -277,27 +327,18 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
static void loadSplatProgram(const char* type, ProgramObject& program, SplatLocations& locations);
|
||||
|
||||
static ProgramObject _pointProgram;
|
||||
static int _pointScaleLocation;
|
||||
|
||||
static ProgramObject _heightfieldProgram;
|
||||
static int _heightScaleLocation;
|
||||
static int _colorScaleLocation;
|
||||
|
||||
static ProgramObject _shadowMapHeightfieldProgram;
|
||||
static int _shadowMapHeightScaleLocation;
|
||||
static int _shadowMapColorScaleLocation;
|
||||
|
||||
static ProgramObject _cascadedShadowMapHeightfieldProgram;
|
||||
static int _cascadedShadowMapHeightScaleLocation;
|
||||
static int _cascadedShadowMapColorScaleLocation;
|
||||
static int _shadowDistancesLocation;
|
||||
|
||||
static ProgramObject _baseHeightfieldProgram;
|
||||
static int _baseHeightScaleLocation;
|
||||
static int _baseColorScaleLocation;
|
||||
|
||||
static ProgramObject _splatHeightfieldProgram;
|
||||
static SplatLocations _splatHeightfieldLocations;
|
||||
|
||||
static int _splatHeightScaleLocation;
|
||||
static int _splatTextureScaleLocation;
|
||||
static int _splatTextureOffsetLocation;
|
||||
|
@ -306,17 +347,11 @@ private:
|
|||
static int _splatTextureValueMinimaLocation;
|
||||
static int _splatTextureValueMaximaLocation;
|
||||
|
||||
static ProgramObject _lightHeightfieldProgram;
|
||||
static int _lightHeightScaleLocation;
|
||||
|
||||
static ProgramObject _shadowLightHeightfieldProgram;
|
||||
static int _shadowLightHeightScaleLocation;
|
||||
|
||||
static ProgramObject _cascadedShadowLightHeightfieldProgram;
|
||||
static int _cascadedShadowLightHeightScaleLocation;
|
||||
static int _shadowLightDistancesLocation;
|
||||
|
||||
static ProgramObject _heightfieldCursorProgram;
|
||||
|
||||
static ProgramObject _baseVoxelProgram;
|
||||
static ProgramObject _splatVoxelProgram;
|
||||
static SplatLocations _splatVoxelLocations;
|
||||
};
|
||||
|
||||
/// Base class for spanner renderers; provides clipping.
|
||||
|
|
|
@ -29,6 +29,7 @@ TextureCache::TextureCache() :
|
|||
_whiteTextureID(0),
|
||||
_blueTextureID(0),
|
||||
_primaryDepthTextureID(0),
|
||||
_primaryNormalTextureID(0),
|
||||
_primaryFramebufferObject(NULL),
|
||||
_secondaryFramebufferObject(NULL),
|
||||
_tertiaryFramebufferObject(NULL),
|
||||
|
@ -46,6 +47,7 @@ TextureCache::~TextureCache() {
|
|||
}
|
||||
if (_primaryFramebufferObject) {
|
||||
glDeleteTextures(1, &_primaryDepthTextureID);
|
||||
glDeleteTextures(1, &_primaryNormalTextureID);
|
||||
}
|
||||
|
||||
if (_primaryFramebufferObject) {
|
||||
|
@ -71,6 +73,8 @@ void TextureCache::setFrameBufferSize(QSize frameBufferSize) {
|
|||
_primaryFramebufferObject = NULL;
|
||||
glDeleteTextures(1, &_primaryDepthTextureID);
|
||||
_primaryDepthTextureID = 0;
|
||||
glDeleteTextures(1, &_primaryNormalTextureID);
|
||||
_primaryNormalTextureID = 0;
|
||||
}
|
||||
|
||||
if (_secondaryFramebufferObject) {
|
||||
|
@ -205,15 +209,22 @@ QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() {
|
|||
|
||||
glGenTextures(1, &_primaryDepthTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, _primaryDepthTextureID);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, _frameBufferSize.width(), _frameBufferSize.height(),
|
||||
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glGenTextures(1, &_primaryNormalTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, _primaryNormalTextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _frameBufferSize.width(), _frameBufferSize.height(),
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
_primaryFramebufferObject->bind();
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _primaryDepthTextureID, 0);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, _primaryNormalTextureID, 0);
|
||||
_primaryFramebufferObject->release();
|
||||
}
|
||||
return _primaryFramebufferObject;
|
||||
|
@ -225,6 +236,12 @@ GLuint TextureCache::getPrimaryDepthTextureID() {
|
|||
return _primaryDepthTextureID;
|
||||
}
|
||||
|
||||
GLuint TextureCache::getPrimaryNormalTextureID() {
|
||||
// ensure that the primary framebuffer object is initialized before returning the normal texture id
|
||||
getPrimaryFramebufferObject();
|
||||
return _primaryNormalTextureID;
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() {
|
||||
if (!_secondaryFramebufferObject) {
|
||||
_secondaryFramebufferObject = createFramebufferObject();
|
||||
|
@ -278,6 +295,7 @@ bool TextureCache::eventFilter(QObject* watched, QEvent* event) {
|
|||
delete _primaryFramebufferObject;
|
||||
_primaryFramebufferObject = NULL;
|
||||
glDeleteTextures(1, &_primaryDepthTextureID);
|
||||
glDeleteTextures(1, &_primaryNormalTextureID);
|
||||
}
|
||||
if (_secondaryFramebufferObject && _secondaryFramebufferObject->size() != size) {
|
||||
delete _secondaryFramebufferObject;
|
||||
|
|
|
@ -61,6 +61,9 @@ public:
|
|||
/// Returns the ID of the primary framebuffer object's depth texture. This contains the Z buffer used in rendering.
|
||||
GLuint getPrimaryDepthTextureID();
|
||||
|
||||
/// Returns the ID of the primary framebuffer object's normal texture.
|
||||
GLuint getPrimaryNormalTextureID();
|
||||
|
||||
/// Returns a pointer to the secondary framebuffer object, used as an additional render target when performing full
|
||||
/// screen effects.
|
||||
QOpenGLFramebufferObject* getSecondaryFramebufferObject();
|
||||
|
@ -95,6 +98,7 @@ private:
|
|||
QHash<QUrl, QWeakPointer<NetworkTexture> > _dilatableNetworkTextures;
|
||||
|
||||
GLuint _primaryDepthTextureID;
|
||||
GLuint _primaryNormalTextureID;
|
||||
QOpenGLFramebufferObject* _primaryFramebufferObject;
|
||||
QOpenGLFramebufferObject* _secondaryFramebufferObject;
|
||||
QOpenGLFramebufferObject* _tertiaryFramebufferObject;
|
||||
|
|
|
@ -66,13 +66,16 @@ MetavoxelEditor::MetavoxelEditor() :
|
|||
attributeLayout->addLayout(attributeButtonLayout);
|
||||
|
||||
QPushButton* newAttribute = new QPushButton("New...");
|
||||
attributeButtonLayout->addWidget(newAttribute);
|
||||
attributeButtonLayout->addWidget(newAttribute, 1);
|
||||
connect(newAttribute, SIGNAL(clicked()), SLOT(createNewAttribute()));
|
||||
|
||||
attributeButtonLayout->addWidget(_deleteAttribute = new QPushButton("Delete"));
|
||||
attributeButtonLayout->addWidget(_deleteAttribute = new QPushButton("Delete"), 1);
|
||||
_deleteAttribute->setEnabled(false);
|
||||
connect(_deleteAttribute, SIGNAL(clicked()), SLOT(deleteSelectedAttribute()));
|
||||
|
||||
attributeButtonLayout->addWidget(_showAll = new QCheckBox("Show All"));
|
||||
connect(_showAll, SIGNAL(clicked()), SLOT(updateAttributes()));
|
||||
|
||||
QFormLayout* formLayout = new QFormLayout();
|
||||
topLayout->addLayout(formLayout);
|
||||
|
||||
|
@ -116,11 +119,15 @@ MetavoxelEditor::MetavoxelEditor() :
|
|||
addTool(new RemoveSpannerTool(this));
|
||||
addTool(new ClearSpannersTool(this));
|
||||
addTool(new SetSpannerTool(this));
|
||||
addTool(new ImportHeightfieldTool(this));
|
||||
addTool(new EraseHeightfieldTool(this));
|
||||
addTool(new HeightfieldHeightBrushTool(this));
|
||||
addTool(new HeightfieldColorBrushTool(this));
|
||||
addTool(new HeightfieldTextureBrushTool(this));
|
||||
addTool(new HeightfieldMaterialBrushTool(this));
|
||||
addTool(new ImportHeightfieldTool(this));
|
||||
addTool(new EraseHeightfieldTool(this));
|
||||
addTool(new VoxelColorBoxTool(this));
|
||||
addTool(new VoxelMaterialBoxTool(this));
|
||||
addTool(new VoxelColorSphereTool(this));
|
||||
addTool(new VoxelMaterialSphereTool(this));
|
||||
|
||||
updateAttributes();
|
||||
|
||||
|
@ -200,7 +207,7 @@ void MetavoxelEditor::selectedAttributeChanged() {
|
|||
|
||||
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(selected);
|
||||
foreach (MetavoxelTool* tool, _tools) {
|
||||
if (tool->appliesTo(attribute)) {
|
||||
if (tool->appliesTo(attribute) && (tool->isUserFacing() || _showAll->isChecked())) {
|
||||
_toolBox->addItem(tool->objectName(), QVariant::fromValue(tool));
|
||||
}
|
||||
}
|
||||
|
@ -214,6 +221,7 @@ void MetavoxelEditor::selectedAttributeChanged() {
|
|||
editor->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
|
||||
_valueArea->setWidget(editor);
|
||||
}
|
||||
updateTool();
|
||||
}
|
||||
|
||||
void MetavoxelEditor::createNewAttribute() {
|
||||
|
@ -271,6 +279,35 @@ void MetavoxelEditor::alignGridPosition() {
|
|||
_gridPosition->setValue(step * floor(_gridPosition->value() / step));
|
||||
}
|
||||
|
||||
void MetavoxelEditor::updateAttributes(const QString& select) {
|
||||
// remember the selection in order to preserve it
|
||||
QString selected = select.isNull() ? getSelectedAttribute() : select;
|
||||
_attributes->clear();
|
||||
|
||||
// sort the names for consistent ordering
|
||||
QList<QString> names;
|
||||
if (_showAll->isChecked()) {
|
||||
names = AttributeRegistry::getInstance()->getAttributes().keys();
|
||||
|
||||
} else {
|
||||
foreach (const AttributePointer& attribute, AttributeRegistry::getInstance()->getAttributes()) {
|
||||
if (attribute->isUserFacing()) {
|
||||
names.append(attribute->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
qSort(names);
|
||||
|
||||
foreach (const QString& name, names) {
|
||||
QListWidgetItem* item = new QListWidgetItem(name);
|
||||
_attributes->addItem(item);
|
||||
if (name == selected || selected.isNull()) {
|
||||
item->setSelected(true);
|
||||
selected = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelEditor::updateTool() {
|
||||
MetavoxelTool* active = getActiveTool();
|
||||
foreach (MetavoxelTool* tool, _tools) {
|
||||
|
@ -335,25 +372,6 @@ void MetavoxelEditor::addTool(MetavoxelTool* tool) {
|
|||
layout()->addWidget(tool);
|
||||
}
|
||||
|
||||
void MetavoxelEditor::updateAttributes(const QString& select) {
|
||||
// remember the selection in order to preserve it
|
||||
QString selected = select.isNull() ? getSelectedAttribute() : select;
|
||||
_attributes->clear();
|
||||
|
||||
// sort the names for consistent ordering
|
||||
QList<QString> names = AttributeRegistry::getInstance()->getAttributes().keys();
|
||||
qSort(names);
|
||||
|
||||
foreach (const QString& name, names) {
|
||||
QListWidgetItem* item = new QListWidgetItem(name);
|
||||
_attributes->addItem(item);
|
||||
if (name == selected || selected.isNull()) {
|
||||
item->setSelected(true);
|
||||
selected = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelTool* MetavoxelEditor::getActiveTool() const {
|
||||
int index = _toolBox->currentIndex();
|
||||
return (index == -1) ? NULL : static_cast<MetavoxelTool*>(_toolBox->itemData(index).value<QObject*>());
|
||||
|
@ -361,9 +379,10 @@ MetavoxelTool* MetavoxelEditor::getActiveTool() const {
|
|||
|
||||
ProgramObject MetavoxelEditor::_gridProgram;
|
||||
|
||||
MetavoxelTool::MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue) :
|
||||
MetavoxelTool::MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue, bool userFacing) :
|
||||
_editor(editor),
|
||||
_usesValue(usesValue) {
|
||||
_usesValue(usesValue),
|
||||
_userFacing(userFacing) {
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
setLayout(layout);
|
||||
|
@ -385,13 +404,13 @@ void MetavoxelTool::render() {
|
|||
// nothing by default
|
||||
}
|
||||
|
||||
BoxSetTool::BoxSetTool(MetavoxelEditor* editor) :
|
||||
MetavoxelTool(editor, "Set Value (Box)") {
|
||||
BoxTool::BoxTool(MetavoxelEditor* editor, const QString& name, bool usesValue, bool userFacing) :
|
||||
MetavoxelTool(editor, name, usesValue, userFacing) {
|
||||
|
||||
resetState();
|
||||
}
|
||||
|
||||
void BoxSetTool::render() {
|
||||
void BoxTool::render() {
|
||||
if (Application::getInstance()->isMouseHidden()) {
|
||||
resetState();
|
||||
return;
|
||||
|
@ -457,7 +476,7 @@ void BoxSetTool::render() {
|
|||
glTranslatef(0.5f, 0.5f, 0.5f);
|
||||
if (_state != HOVERING_STATE) {
|
||||
const float BOX_ALPHA = 0.25f;
|
||||
QColor color = _editor->getValue().value<QColor>();
|
||||
QColor color = getColor();
|
||||
if (color.isValid()) {
|
||||
glColor4f(color.redF(), color.greenF(), color.blueF(), BOX_ALPHA);
|
||||
} else {
|
||||
|
@ -476,7 +495,7 @@ void BoxSetTool::render() {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
bool BoxSetTool::eventFilter(QObject* watched, QEvent* event) {
|
||||
bool BoxTool::eventFilter(QObject* watched, QEvent* event) {
|
||||
switch (_state) {
|
||||
case HOVERING_STATE:
|
||||
if (event->type() == QEvent::MouseButtonPress && _startPosition != INVALID_VECTOR) {
|
||||
|
@ -515,12 +534,20 @@ bool BoxSetTool::eventFilter(QObject* watched, QEvent* event) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void BoxSetTool::resetState() {
|
||||
void BoxTool::resetState() {
|
||||
_state = HOVERING_STATE;
|
||||
_startPosition = INVALID_VECTOR;
|
||||
_height = 0.0f;
|
||||
}
|
||||
|
||||
BoxSetTool::BoxSetTool(MetavoxelEditor* editor) :
|
||||
BoxTool(editor, "Set Value (Box)", true, false) {
|
||||
}
|
||||
|
||||
QColor BoxSetTool::getColor() {
|
||||
return _editor->getValue().value<QColor>();
|
||||
}
|
||||
|
||||
void BoxSetTool::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) {
|
||||
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute());
|
||||
if (!attribute) {
|
||||
|
@ -533,7 +560,7 @@ void BoxSetTool::applyValue(const glm::vec3& minimum, const glm::vec3& maximum)
|
|||
}
|
||||
|
||||
GlobalSetTool::GlobalSetTool(MetavoxelEditor* editor) :
|
||||
MetavoxelTool(editor, "Set Value (Global)") {
|
||||
MetavoxelTool(editor, "Set Value (Global)", true, false) {
|
||||
|
||||
QPushButton* button = new QPushButton("Apply");
|
||||
layout()->addWidget(button);
|
||||
|
@ -944,11 +971,9 @@ ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) :
|
|||
connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile);
|
||||
_form->addRow("Color:", _color = new QPushButton());
|
||||
connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile);
|
||||
}
|
||||
|
||||
void ImportHeightfieldTool::render() {
|
||||
HeightfieldTool::render();
|
||||
_preview.render(_translation->getValue(), _translation->getSingleStep());
|
||||
|
||||
connect(Application::getInstance()->getMetavoxels(), &MetavoxelSystem::rendering,
|
||||
this, &ImportHeightfieldTool::renderPreview);
|
||||
}
|
||||
|
||||
void ImportHeightfieldTool::apply() {
|
||||
|
@ -966,7 +991,7 @@ void ImportHeightfieldTool::apply() {
|
|||
QByteArray color;
|
||||
if (buffer->getColor().isEmpty()) {
|
||||
const int WHITE_VALUE = 0xFF;
|
||||
color = QByteArray(height.size() * HeightfieldData::COLOR_BYTES, WHITE_VALUE);
|
||||
color = QByteArray(height.size() * DataBlock::COLOR_BYTES, WHITE_VALUE);
|
||||
} else {
|
||||
color = buffer->getUnextendedColor();
|
||||
}
|
||||
|
@ -975,10 +1000,10 @@ void ImportHeightfieldTool::apply() {
|
|||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer))));
|
||||
|
||||
int size = glm::sqrt(height.size()) + HeightfieldBuffer::SHARED_EDGE;
|
||||
QByteArray texture(size * size, 0);
|
||||
HeightfieldTextureDataPointer texturePointer(new HeightfieldTextureData(texture));
|
||||
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldTextureAttribute(), new MetavoxelNode(AttributeValue(
|
||||
AttributeRegistry::getInstance()->getHeightfieldTextureAttribute(), encodeInline(texturePointer))));
|
||||
QByteArray material(size * size, 0);
|
||||
HeightfieldMaterialDataPointer materialPointer(new HeightfieldMaterialData(material));
|
||||
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute(), new MetavoxelNode(AttributeValue(
|
||||
AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute(), encodeInline(materialPointer))));
|
||||
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(SetDataEdit(
|
||||
_translation->getValue() + buffer->getTranslation() * scale, data)) };
|
||||
|
@ -1032,22 +1057,22 @@ void ImportHeightfieldTool::updatePreview() {
|
|||
int rows = qMin(heightSize - offsetY, _heightImage.height() - extendedI);
|
||||
int columns = qMin(heightSize - offsetX, _heightImage.width() - extendedJ);
|
||||
for (int y = 0; y < rows; y++) {
|
||||
uchar* src = _heightImage.scanLine(extendedI + y) + extendedJ * HeightfieldData::COLOR_BYTES;
|
||||
uchar* src = _heightImage.scanLine(extendedI + y) + extendedJ * DataBlock::COLOR_BYTES;
|
||||
char* dest = height.data() + (y + offsetY) * heightSize + offsetX;
|
||||
for (int x = 0; x < columns; x++) {
|
||||
*dest++ = *src;
|
||||
src += HeightfieldData::COLOR_BYTES;
|
||||
src += DataBlock::COLOR_BYTES;
|
||||
}
|
||||
}
|
||||
QByteArray color;
|
||||
if (!_colorImage.isNull()) {
|
||||
color = QByteArray(colorSize * colorSize * HeightfieldData::COLOR_BYTES, 0);
|
||||
color = QByteArray(colorSize * colorSize * DataBlock::COLOR_BYTES, 0);
|
||||
rows = qMax(0, qMin(colorSize, _colorImage.height() - i));
|
||||
columns = qMax(0, qMin(colorSize, _colorImage.width() - j));
|
||||
for (int y = 0; y < rows; y++) {
|
||||
memcpy(color.data() + y * colorSize * HeightfieldData::COLOR_BYTES,
|
||||
_colorImage.scanLine(i + y) + j * HeightfieldData::COLOR_BYTES,
|
||||
columns * HeightfieldData::COLOR_BYTES);
|
||||
memcpy(color.data() + y * colorSize * DataBlock::COLOR_BYTES,
|
||||
_colorImage.scanLine(i + y) + j * DataBlock::COLOR_BYTES,
|
||||
columns * DataBlock::COLOR_BYTES);
|
||||
}
|
||||
}
|
||||
buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color)));
|
||||
|
@ -1057,6 +1082,12 @@ void ImportHeightfieldTool::updatePreview() {
|
|||
_preview.setBuffers(buffers);
|
||||
}
|
||||
|
||||
void ImportHeightfieldTool::renderPreview() {
|
||||
if (isVisible()) {
|
||||
_preview.render(_translation->getValue(), _translation->getSingleStep());
|
||||
}
|
||||
}
|
||||
|
||||
EraseHeightfieldTool::EraseHeightfieldTool(MetavoxelEditor* editor) :
|
||||
HeightfieldTool(editor, "Erase Heightfield") {
|
||||
|
||||
|
@ -1177,25 +1208,190 @@ QVariant HeightfieldColorBrushTool::createEdit(bool alternate) {
|
|||
alternate ? QColor() : _color->getColor()));
|
||||
}
|
||||
|
||||
HeightfieldTextureBrushTool::HeightfieldTextureBrushTool(MetavoxelEditor* editor) :
|
||||
HeightfieldBrushTool(editor, "Texture Brush") {
|
||||
HeightfieldMaterialBrushTool::HeightfieldMaterialBrushTool(MetavoxelEditor* editor) :
|
||||
HeightfieldBrushTool(editor, "Material Brush") {
|
||||
|
||||
_form->addRow(_textureEditor = new SharedObjectEditor(&HeightfieldTexture::staticMetaObject, false));
|
||||
connect(_textureEditor, &SharedObjectEditor::objectChanged, this, &HeightfieldTextureBrushTool::updateTexture);
|
||||
_form->addRow(_materialEditor = new SharedObjectEditor(&MaterialObject::staticMetaObject, false));
|
||||
connect(_materialEditor, &SharedObjectEditor::objectChanged, this, &HeightfieldMaterialBrushTool::updateTexture);
|
||||
}
|
||||
|
||||
QVariant HeightfieldTextureBrushTool::createEdit(bool alternate) {
|
||||
QVariant HeightfieldMaterialBrushTool::createEdit(bool alternate) {
|
||||
if (alternate) {
|
||||
return QVariant::fromValue(PaintHeightfieldTextureEdit(_position, _radius->value(), SharedObjectPointer(), QColor()));
|
||||
return QVariant::fromValue(PaintHeightfieldMaterialEdit(_position, _radius->value(), SharedObjectPointer(), QColor()));
|
||||
} else {
|
||||
SharedObjectPointer texture = _textureEditor->getObject();
|
||||
_textureEditor->detachObject();
|
||||
return QVariant::fromValue(PaintHeightfieldTextureEdit(_position, _radius->value(), texture,
|
||||
SharedObjectPointer material = _materialEditor->getObject();
|
||||
_materialEditor->detachObject();
|
||||
return QVariant::fromValue(PaintHeightfieldMaterialEdit(_position, _radius->value(), material,
|
||||
_texture ? _texture->getAverageColor() : QColor()));
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldTextureBrushTool::updateTexture() {
|
||||
HeightfieldTexture* texture = static_cast<HeightfieldTexture*>(_textureEditor->getObject().data());
|
||||
_texture = Application::getInstance()->getTextureCache()->getTexture(texture->getURL());
|
||||
void HeightfieldMaterialBrushTool::updateTexture() {
|
||||
MaterialObject* material = static_cast<MaterialObject*>(_materialEditor->getObject().data());
|
||||
_texture = Application::getInstance()->getTextureCache()->getTexture(material->getDiffuse(), SPLAT_TEXTURE);
|
||||
}
|
||||
|
||||
VoxelColorBoxTool::VoxelColorBoxTool(MetavoxelEditor* editor) :
|
||||
BoxTool(editor, "Set Voxel Color (Box)", false) {
|
||||
|
||||
QWidget* widget = new QWidget();
|
||||
QFormLayout* form = new QFormLayout();
|
||||
widget->setLayout(form);
|
||||
layout()->addWidget(widget);
|
||||
|
||||
form->addRow("Color:", _color = new QColorEditor(this));
|
||||
}
|
||||
|
||||
bool VoxelColorBoxTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute->inherits("VoxelColorAttribute");
|
||||
}
|
||||
|
||||
QColor VoxelColorBoxTool::getColor() {
|
||||
return _color->getColor();
|
||||
}
|
||||
|
||||
void VoxelColorBoxTool::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) {
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(VoxelColorBoxEdit(Box(minimum, maximum),
|
||||
_editor->getGridSpacing(), _color->getColor())) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
}
|
||||
|
||||
VoxelMaterialBoxTool::VoxelMaterialBoxTool(MetavoxelEditor* editor) :
|
||||
BoxTool(editor, "Set Voxel Material (Box)", false) {
|
||||
|
||||
QWidget* widget = new QWidget();
|
||||
QFormLayout* form = new QFormLayout();
|
||||
widget->setLayout(form);
|
||||
layout()->addWidget(widget);
|
||||
|
||||
form->addRow(_materialEditor = new SharedObjectEditor(&MaterialObject::staticMetaObject, false));
|
||||
connect(_materialEditor, &SharedObjectEditor::objectChanged, this, &VoxelMaterialBoxTool::updateTexture);
|
||||
}
|
||||
|
||||
bool VoxelMaterialBoxTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute->inherits("VoxelColorAttribute");
|
||||
}
|
||||
|
||||
QColor VoxelMaterialBoxTool::getColor() {
|
||||
return _texture ? _texture->getAverageColor() : QColor();
|
||||
}
|
||||
|
||||
void VoxelMaterialBoxTool::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) {
|
||||
SharedObjectPointer material = _materialEditor->getObject();
|
||||
_materialEditor->detachObject();
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialBoxEdit(Box(minimum, maximum),
|
||||
_editor->getGridSpacing(), material, _texture ? _texture->getAverageColor() : QColor())) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
}
|
||||
|
||||
void VoxelMaterialBoxTool::updateTexture() {
|
||||
MaterialObject* material = static_cast<MaterialObject*>(_materialEditor->getObject().data());
|
||||
_texture = Application::getInstance()->getTextureCache()->getTexture(material->getDiffuse(), SPLAT_TEXTURE);
|
||||
}
|
||||
|
||||
SphereTool::SphereTool(MetavoxelEditor* editor, const QString& name) :
|
||||
MetavoxelTool(editor, name, false, true) {
|
||||
|
||||
QWidget* widget = new QWidget();
|
||||
widget->setLayout(_form = new QFormLayout());
|
||||
layout()->addWidget(widget);
|
||||
|
||||
_form->addRow("Radius:", _radius = new QDoubleSpinBox());
|
||||
_radius->setSingleStep(0.01);
|
||||
_radius->setMaximum(FLT_MAX);
|
||||
_radius->setValue(1.0);
|
||||
}
|
||||
|
||||
void SphereTool::render() {
|
||||
if (Application::getInstance()->isMouseHidden()) {
|
||||
return;
|
||||
}
|
||||
glm::quat rotation = _editor->getGridRotation();
|
||||
glm::quat inverseRotation = glm::inverse(rotation);
|
||||
glm::vec3 rayOrigin = inverseRotation * Application::getInstance()->getMouseRayOrigin();
|
||||
glm::vec3 rayDirection = inverseRotation * Application::getInstance()->getMouseRayDirection();
|
||||
float position = _editor->getGridPosition();
|
||||
if (glm::abs(rayDirection.z) < EPSILON) {
|
||||
return;
|
||||
}
|
||||
float distance = (position - rayOrigin.z) / rayDirection.z;
|
||||
_position = Application::getInstance()->getMouseRayOrigin() +
|
||||
Application::getInstance()->getMouseRayDirection() * distance;
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
|
||||
const float CURSOR_ALPHA = 0.5f;
|
||||
QColor color = getColor();
|
||||
glColor4f(color.redF(), color.greenF(), color.blueF(), CURSOR_ALPHA);
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
glutSolidSphere(_radius->value(), 10, 10);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
bool SphereTool::eventFilter(QObject* watched, QEvent* event) {
|
||||
if (event->type() == QEvent::Wheel) {
|
||||
float angle = static_cast<QWheelEvent*>(event)->angleDelta().y();
|
||||
const float ANGLE_SCALE = 1.0f / 1000.0f;
|
||||
_radius->setValue(_radius->value() * glm::pow(2.0f, angle * ANGLE_SCALE));
|
||||
return true;
|
||||
|
||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||
applyValue(_position, _radius->value());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VoxelColorSphereTool::VoxelColorSphereTool(MetavoxelEditor* editor) :
|
||||
SphereTool(editor, "Set Voxel Color (Sphere)") {
|
||||
|
||||
_form->addRow("Color:", _color = new QColorEditor(this));
|
||||
}
|
||||
|
||||
bool VoxelColorSphereTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute->inherits("VoxelColorAttribute");
|
||||
}
|
||||
|
||||
QColor VoxelColorSphereTool::getColor() {
|
||||
return _color->getColor();
|
||||
}
|
||||
|
||||
void VoxelColorSphereTool::applyValue(const glm::vec3& position, float radius) {
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(VoxelColorSphereEdit(position, radius,
|
||||
_editor->getGridSpacing(), _color->getColor())) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
}
|
||||
|
||||
VoxelMaterialSphereTool::VoxelMaterialSphereTool(MetavoxelEditor* editor) :
|
||||
SphereTool(editor, "Set Voxel Material (Sphere)") {
|
||||
|
||||
_form->addRow(_materialEditor = new SharedObjectEditor(&MaterialObject::staticMetaObject, false));
|
||||
connect(_materialEditor, &SharedObjectEditor::objectChanged, this, &VoxelMaterialSphereTool::updateTexture);
|
||||
}
|
||||
|
||||
bool VoxelMaterialSphereTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute->inherits("VoxelColorAttribute");
|
||||
}
|
||||
|
||||
QColor VoxelMaterialSphereTool::getColor() {
|
||||
return _texture ? _texture->getAverageColor() : QColor();
|
||||
}
|
||||
|
||||
void VoxelMaterialSphereTool::applyValue(const glm::vec3& position, float radius) {
|
||||
SharedObjectPointer material = _materialEditor->getObject();
|
||||
_materialEditor->detachObject();
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSphereEdit(position, radius,
|
||||
_editor->getGridSpacing(), material, _texture ? _texture->getAverageColor() : QColor())) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
}
|
||||
|
||||
void VoxelMaterialSphereTool::updateTexture() {
|
||||
MaterialObject* material = static_cast<MaterialObject*>(_materialEditor->getObject().data());
|
||||
_texture = Application::getInstance()->getTextureCache()->getTexture(material->getDiffuse(), SPLAT_TEXTURE);
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ private slots:
|
|||
void deleteSelectedAttribute();
|
||||
void centerGridPosition();
|
||||
void alignGridPosition();
|
||||
void updateAttributes(const QString& select = QString());
|
||||
void updateTool();
|
||||
|
||||
void simulate(float deltaTime);
|
||||
|
@ -65,11 +66,11 @@ private slots:
|
|||
private:
|
||||
|
||||
void addTool(MetavoxelTool* tool);
|
||||
void updateAttributes(const QString& select = QString());
|
||||
MetavoxelTool* getActiveTool() const;
|
||||
|
||||
QListWidget* _attributes;
|
||||
QPushButton* _deleteAttribute;
|
||||
QCheckBox* _showAll;
|
||||
|
||||
QComboBox* _gridPlane;
|
||||
QDoubleSpinBox* _gridSpacing;
|
||||
|
@ -90,10 +91,12 @@ class MetavoxelTool : public QWidget {
|
|||
|
||||
public:
|
||||
|
||||
MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true);
|
||||
MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true, bool userFacing = true);
|
||||
|
||||
bool getUsesValue() const { return _usesValue; }
|
||||
|
||||
bool isUserFacing() const { return _userFacing; }
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
virtual void simulate(float deltaTime);
|
||||
|
@ -105,24 +108,30 @@ protected:
|
|||
|
||||
MetavoxelEditor* _editor;
|
||||
bool _usesValue;
|
||||
bool _userFacing;
|
||||
};
|
||||
|
||||
/// Allows setting the value of a region by dragging out a box.
|
||||
class BoxSetTool : public MetavoxelTool {
|
||||
/// Base class for tools that allow dragging out a 3D box.
|
||||
class BoxTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
BoxSetTool(MetavoxelEditor* editor);
|
||||
|
||||
BoxTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true, bool userFacing = true);
|
||||
|
||||
virtual void render();
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor() = 0;
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum) = 0;
|
||||
|
||||
private:
|
||||
|
||||
void resetState();
|
||||
void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
|
||||
enum State { HOVERING_STATE, DRAGGING_STATE, RAISING_STATE };
|
||||
|
||||
|
@ -134,6 +143,21 @@ private:
|
|||
float _height; ///< the selection height
|
||||
};
|
||||
|
||||
/// Allows setting the value of a region by dragging out a box.
|
||||
class BoxSetTool : public BoxTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
BoxSetTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor();
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
};
|
||||
|
||||
/// Allows setting the value across the entire space.
|
||||
class GlobalSetTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
@ -259,8 +283,6 @@ public:
|
|||
|
||||
ImportHeightfieldTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual void render();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void apply();
|
||||
|
@ -270,6 +292,7 @@ private slots:
|
|||
void selectHeightFile();
|
||||
void selectColorFile();
|
||||
void updatePreview();
|
||||
void renderPreview();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -363,12 +386,12 @@ private:
|
|||
};
|
||||
|
||||
/// Allows texturing parts of the heightfield.
|
||||
class HeightfieldTextureBrushTool : public HeightfieldBrushTool {
|
||||
class HeightfieldMaterialBrushTool : public HeightfieldBrushTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldTextureBrushTool(MetavoxelEditor* editor);
|
||||
HeightfieldMaterialBrushTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -380,7 +403,125 @@ private slots:
|
|||
|
||||
private:
|
||||
|
||||
SharedObjectEditor* _textureEditor;
|
||||
SharedObjectEditor* _materialEditor;
|
||||
QSharedPointer<NetworkTexture> _texture;
|
||||
};
|
||||
|
||||
/// Allows setting voxel colors by dragging out a box.
|
||||
class VoxelColorBoxTool : public BoxTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
VoxelColorBoxTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor();
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
|
||||
private:
|
||||
|
||||
QColorEditor* _color;
|
||||
};
|
||||
|
||||
/// Allows setting voxel materials by dragging out a box.
|
||||
class VoxelMaterialBoxTool : public BoxTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
VoxelMaterialBoxTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor();
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
|
||||
private slots:
|
||||
|
||||
void updateTexture();
|
||||
|
||||
private:
|
||||
|
||||
SharedObjectEditor* _materialEditor;
|
||||
QSharedPointer<NetworkTexture> _texture;
|
||||
};
|
||||
|
||||
/// Base class for tools based on a sphere brush.
|
||||
class SphereTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
SphereTool(MetavoxelEditor* editor, const QString& name);
|
||||
|
||||
virtual void render();
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor() = 0;
|
||||
|
||||
virtual void applyValue(const glm::vec3& position, float radius) = 0;
|
||||
|
||||
QFormLayout* _form;
|
||||
QDoubleSpinBox* _radius;
|
||||
|
||||
glm::vec3 _position;
|
||||
};
|
||||
|
||||
/// Allows setting voxel colors by moving a sphere around.
|
||||
class VoxelColorSphereTool : public SphereTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
VoxelColorSphereTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor();
|
||||
|
||||
virtual void applyValue(const glm::vec3& position, float radius);
|
||||
|
||||
private:
|
||||
|
||||
QColorEditor* _color;
|
||||
};
|
||||
|
||||
/// Allows setting voxel materials by moving a sphere around.
|
||||
class VoxelMaterialSphereTool : public SphereTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
VoxelMaterialSphereTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor();
|
||||
|
||||
virtual void applyValue(const glm::vec3& position, float radius);
|
||||
|
||||
private slots:
|
||||
|
||||
void updateTexture();
|
||||
|
||||
private:
|
||||
|
||||
SharedObjectEditor* _materialEditor;
|
||||
QSharedPointer<NetworkTexture> _texture;
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,14 +29,17 @@ class QScriptEngine;
|
|||
class QScriptValue;
|
||||
|
||||
class Attribute;
|
||||
class DataBlock;
|
||||
class HeightfieldColorData;
|
||||
class HeightfieldData;
|
||||
class HeightfieldHeightData;
|
||||
class HeightfieldTextureData;
|
||||
class HeightfieldMaterialData;
|
||||
class MetavoxelData;
|
||||
class MetavoxelLOD;
|
||||
class MetavoxelNode;
|
||||
class MetavoxelStreamState;
|
||||
class VoxelColorData;
|
||||
class VoxelHermiteData;
|
||||
class VoxelMaterialData;
|
||||
|
||||
typedef SharedObjectPointerTemplate<Attribute> AttributePointer;
|
||||
|
||||
|
@ -100,14 +103,23 @@ public:
|
|||
/// Returns a reference to the standard "spannerMask" attribute.
|
||||
const AttributePointer& getSpannerMaskAttribute() const { return _spannerMaskAttribute; }
|
||||
|
||||
/// Returns a reference to the standard HeightfieldDataPointer "heightfield" attribute.
|
||||
/// Returns a reference to the standard HeightfieldHeightDataPointer "heightfield" attribute.
|
||||
const AttributePointer& getHeightfieldAttribute() const { return _heightfieldAttribute; }
|
||||
|
||||
/// Returns a reference to the standard HeightfieldDataPointer "heightfieldColor" attribute.
|
||||
/// Returns a reference to the standard HeightfieldColorDataPointer "heightfieldColor" attribute.
|
||||
const AttributePointer& getHeightfieldColorAttribute() const { return _heightfieldColorAttribute; }
|
||||
|
||||
/// Returns a reference to the standard HeightfieldDataPointer "heightfieldTexture" attribute.
|
||||
const AttributePointer& getHeightfieldTextureAttribute() const { return _heightfieldTextureAttribute; }
|
||||
/// Returns a reference to the standard HeightfieldMaterialDataPointer "heightfieldMaterial" attribute.
|
||||
const AttributePointer& getHeightfieldMaterialAttribute() const { return _heightfieldMaterialAttribute; }
|
||||
|
||||
/// Returns a reference to the standard VoxelColorDataPointer "voxelColor" attribute.
|
||||
const AttributePointer& getVoxelColorAttribute() const { return _voxelColorAttribute; }
|
||||
|
||||
/// Returns a reference to the standard VoxelMaterialDataPointer "voxelMaterial" attribute.
|
||||
const AttributePointer& getVoxelMaterialAttribute() const { return _voxelMaterialAttribute; }
|
||||
|
||||
/// Returns a reference to the standard VoxelHermiteDataPointer "voxelHermite" attribute.
|
||||
const AttributePointer& getVoxelHermiteAttribute() const { return _voxelHermiteAttribute; }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -126,7 +138,10 @@ private:
|
|||
AttributePointer _spannerMaskAttribute;
|
||||
AttributePointer _heightfieldAttribute;
|
||||
AttributePointer _heightfieldColorAttribute;
|
||||
AttributePointer _heightfieldTextureAttribute;
|
||||
AttributePointer _heightfieldMaterialAttribute;
|
||||
AttributePointer _voxelColorAttribute;
|
||||
AttributePointer _voxelMaterialAttribute;
|
||||
AttributePointer _voxelHermiteAttribute;
|
||||
};
|
||||
|
||||
/// Converts a value to a void pointer.
|
||||
|
@ -206,6 +221,7 @@ Q_DECLARE_METATYPE(OwnedAttributeValue)
|
|||
class Attribute : public SharedObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float lodThresholdMultiplier MEMBER _lodThresholdMultiplier)
|
||||
Q_PROPERTY(bool userFacing MEMBER _userFacing)
|
||||
|
||||
public:
|
||||
|
||||
|
@ -219,6 +235,9 @@ public:
|
|||
float getLODThresholdMultiplier() const { return _lodThresholdMultiplier; }
|
||||
void setLODThresholdMultiplier(float multiplier) { _lodThresholdMultiplier = multiplier; }
|
||||
|
||||
bool isUserFacing() const { return _userFacing; }
|
||||
void setUserFacing(bool userFacing) { _userFacing = userFacing; }
|
||||
|
||||
void* create() const { return create(getDefaultValue()); }
|
||||
virtual void* create(void* copy) const = 0;
|
||||
virtual void destroy(void* value) const = 0;
|
||||
|
@ -283,6 +302,7 @@ public:
|
|||
private:
|
||||
|
||||
float _lodThresholdMultiplier;
|
||||
bool _userFacing;
|
||||
};
|
||||
|
||||
/// A simple attribute class that stores its values inline.
|
||||
|
@ -396,6 +416,9 @@ public:
|
|||
/// Packs a normal into an RGB value.
|
||||
QRgb packNormal(const glm::vec3& normal);
|
||||
|
||||
/// Packs a normal (plus extra alpha value) into an RGBA value.
|
||||
QRgb packNormal(const glm::vec3& normal, int alpha);
|
||||
|
||||
/// Unpacks a normal from an RGB value.
|
||||
glm::vec3 unpackNormal(QRgb value);
|
||||
|
||||
|
@ -435,21 +458,18 @@ public:
|
|||
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer;
|
||||
typedef QExplicitlySharedDataPointer<DataBlock> DataBlockPointer;
|
||||
|
||||
/// Contains a block of heightfield data.
|
||||
class HeightfieldData : public QSharedData {
|
||||
/// Base class for blocks of data.
|
||||
class DataBlock : public QSharedData {
|
||||
public:
|
||||
|
||||
static const int COLOR_BYTES = 3;
|
||||
|
||||
HeightfieldData(const QByteArray& contents = QByteArray());
|
||||
virtual ~HeightfieldData();
|
||||
virtual ~DataBlock();
|
||||
|
||||
const QByteArray& getContents() const { return _contents; }
|
||||
|
||||
void setDeltaData(const HeightfieldDataPointer& deltaData) { _deltaData = deltaData; }
|
||||
const HeightfieldDataPointer& getDeltaData() const { return _deltaData; }
|
||||
void setDeltaData(const DataBlockPointer& deltaData) { _deltaData = deltaData; }
|
||||
const DataBlockPointer& getDeltaData() const { return _deltaData; }
|
||||
|
||||
void setEncodedDelta(const QByteArray& encodedDelta) { _encodedDelta = encodedDelta; }
|
||||
const QByteArray& getEncodedDelta() const { return _encodedDelta; }
|
||||
|
@ -458,17 +478,16 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
QByteArray _contents;
|
||||
QByteArray _encoded;
|
||||
QMutex _encodedMutex;
|
||||
|
||||
HeightfieldDataPointer _deltaData;
|
||||
DataBlockPointer _deltaData;
|
||||
QByteArray _encodedDelta;
|
||||
QMutex _encodedDeltaMutex;
|
||||
|
||||
class EncodedSubdivision {
|
||||
public:
|
||||
HeightfieldDataPointer ancestor;
|
||||
DataBlockPointer ancestor;
|
||||
QByteArray data;
|
||||
};
|
||||
QVector<EncodedSubdivision> _encodedSubdivisions;
|
||||
|
@ -478,7 +497,7 @@ protected:
|
|||
typedef QExplicitlySharedDataPointer<HeightfieldHeightData> HeightfieldHeightDataPointer;
|
||||
|
||||
/// Contains a block of heightfield height data.
|
||||
class HeightfieldHeightData : public HeightfieldData {
|
||||
class HeightfieldHeightData : public DataBlock {
|
||||
public:
|
||||
|
||||
HeightfieldHeightData(const QByteArray& contents);
|
||||
|
@ -487,6 +506,8 @@ public:
|
|||
HeightfieldHeightData(Bitstream& in, int bytes, const HeightfieldHeightDataPointer& ancestor,
|
||||
const glm::vec3& minimum, float size);
|
||||
|
||||
const QByteArray& getContents() const { return _contents; }
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const HeightfieldHeightDataPointer& reference);
|
||||
void writeSubdivided(Bitstream& out, const HeightfieldHeightDataPointer& ancestor,
|
||||
|
@ -496,75 +517,8 @@ private:
|
|||
|
||||
void read(Bitstream& in, int bytes);
|
||||
void set(const QImage& image);
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<HeightfieldColorData> HeightfieldColorDataPointer;
|
||||
|
||||
/// Contains a block of heightfield color data.
|
||||
class HeightfieldColorData : public HeightfieldData {
|
||||
public:
|
||||
|
||||
HeightfieldColorData(const QByteArray& contents);
|
||||
HeightfieldColorData(Bitstream& in, int bytes);
|
||||
HeightfieldColorData(Bitstream& in, int bytes, const HeightfieldColorDataPointer& reference);
|
||||
HeightfieldColorData(Bitstream& in, int bytes, const HeightfieldColorDataPointer& ancestor,
|
||||
const glm::vec3& minimum, float size);
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const HeightfieldColorDataPointer& reference);
|
||||
void writeSubdivided(Bitstream& out, const HeightfieldColorDataPointer& ancestor,
|
||||
const glm::vec3& minimum, float size);
|
||||
|
||||
private:
|
||||
|
||||
void read(Bitstream& in, int bytes);
|
||||
void set(const QImage& image);
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<HeightfieldTextureData> HeightfieldTextureDataPointer;
|
||||
|
||||
/// Contains a block of heightfield texture data.
|
||||
class HeightfieldTextureData : public HeightfieldData {
|
||||
public:
|
||||
|
||||
HeightfieldTextureData(const QByteArray& contents,
|
||||
const QVector<SharedObjectPointer>& textures = QVector<SharedObjectPointer>());
|
||||
HeightfieldTextureData(Bitstream& in, int bytes);
|
||||
HeightfieldTextureData(Bitstream& in, int bytes, const HeightfieldTextureDataPointer& reference);
|
||||
|
||||
const QVector<SharedObjectPointer>& getTextures() const { return _textures; }
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const HeightfieldTextureDataPointer& reference);
|
||||
|
||||
private:
|
||||
|
||||
void read(Bitstream& in, int bytes);
|
||||
|
||||
QVector<SharedObjectPointer> _textures;
|
||||
};
|
||||
|
||||
/// Contains the description of a heightfield texture.
|
||||
class HeightfieldTexture : public SharedObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QUrl url MEMBER _url)
|
||||
Q_PROPERTY(float scaleS MEMBER _scaleS)
|
||||
Q_PROPERTY(float scaleT MEMBER _scaleT)
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE HeightfieldTexture();
|
||||
|
||||
const QUrl& getURL() const { return _url; }
|
||||
|
||||
float getScaleS() const { return _scaleS; }
|
||||
float getScaleT() const { return _scaleT; }
|
||||
|
||||
private:
|
||||
|
||||
QUrl _url;
|
||||
float _scaleS;
|
||||
float _scaleT;
|
||||
QByteArray _contents;
|
||||
};
|
||||
|
||||
/// An attribute that stores heightfield data.
|
||||
|
@ -584,6 +538,33 @@ public:
|
|||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<HeightfieldColorData> HeightfieldColorDataPointer;
|
||||
|
||||
/// Contains a block of heightfield color data.
|
||||
class HeightfieldColorData : public DataBlock {
|
||||
public:
|
||||
|
||||
HeightfieldColorData(const QByteArray& contents);
|
||||
HeightfieldColorData(Bitstream& in, int bytes);
|
||||
HeightfieldColorData(Bitstream& in, int bytes, const HeightfieldColorDataPointer& reference);
|
||||
HeightfieldColorData(Bitstream& in, int bytes, const HeightfieldColorDataPointer& ancestor,
|
||||
const glm::vec3& minimum, float size);
|
||||
|
||||
const QByteArray& getContents() const { return _contents; }
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const HeightfieldColorDataPointer& reference);
|
||||
void writeSubdivided(Bitstream& out, const HeightfieldColorDataPointer& ancestor,
|
||||
const glm::vec3& minimum, float size);
|
||||
|
||||
private:
|
||||
|
||||
void read(Bitstream& in, int bytes);
|
||||
void set(const QImage& image);
|
||||
|
||||
QByteArray _contents;
|
||||
};
|
||||
|
||||
/// An attribute that stores heightfield colors.
|
||||
class HeightfieldColorAttribute : public InlineAttribute<HeightfieldColorDataPointer> {
|
||||
Q_OBJECT
|
||||
|
@ -601,13 +582,194 @@ public:
|
|||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
};
|
||||
|
||||
/// An attribute that stores heightfield textures.
|
||||
class HeightfieldTextureAttribute : public InlineAttribute<HeightfieldTextureDataPointer> {
|
||||
typedef QExplicitlySharedDataPointer<HeightfieldMaterialData> HeightfieldMaterialDataPointer;
|
||||
|
||||
/// Contains a block of heightfield material data.
|
||||
class HeightfieldMaterialData : public DataBlock {
|
||||
public:
|
||||
|
||||
HeightfieldMaterialData(const QByteArray& contents,
|
||||
const QVector<SharedObjectPointer>& materials = QVector<SharedObjectPointer>());
|
||||
HeightfieldMaterialData(Bitstream& in, int bytes);
|
||||
HeightfieldMaterialData(Bitstream& in, int bytes, const HeightfieldMaterialDataPointer& reference);
|
||||
|
||||
const QByteArray& getContents() const { return _contents; }
|
||||
|
||||
const QVector<SharedObjectPointer>& getMaterials() const { return _materials; }
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const HeightfieldMaterialDataPointer& reference);
|
||||
|
||||
private:
|
||||
|
||||
void read(Bitstream& in, int bytes);
|
||||
|
||||
QByteArray _contents;
|
||||
QVector<SharedObjectPointer> _materials;
|
||||
};
|
||||
|
||||
/// Contains the description of a material.
|
||||
class MaterialObject : public SharedObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QUrl diffuse MEMBER _diffuse)
|
||||
Q_PROPERTY(float scaleS MEMBER _scaleS)
|
||||
Q_PROPERTY(float scaleT MEMBER _scaleT)
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE MaterialObject();
|
||||
|
||||
const QUrl& getDiffuse() const { return _diffuse; }
|
||||
|
||||
float getScaleS() const { return _scaleS; }
|
||||
float getScaleT() const { return _scaleT; }
|
||||
|
||||
private:
|
||||
|
||||
QUrl _diffuse;
|
||||
float _scaleS;
|
||||
float _scaleT;
|
||||
};
|
||||
|
||||
/// An attribute that stores heightfield materials.
|
||||
class HeightfieldMaterialAttribute : public InlineAttribute<HeightfieldMaterialDataPointer> {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE HeightfieldTextureAttribute(const QString& name = QString());
|
||||
Q_INVOKABLE HeightfieldMaterialAttribute(const QString& name = QString());
|
||||
|
||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
||||
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
|
||||
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
|
||||
|
||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<VoxelColorData> VoxelColorDataPointer;
|
||||
|
||||
/// Contains a block of voxel color data.
|
||||
class VoxelColorData : public DataBlock {
|
||||
public:
|
||||
|
||||
VoxelColorData(const QVector<QRgb>& contents, int size);
|
||||
VoxelColorData(Bitstream& in, int bytes);
|
||||
VoxelColorData(Bitstream& in, int bytes, const VoxelColorDataPointer& reference);
|
||||
|
||||
const QVector<QRgb>& getContents() const { return _contents; }
|
||||
|
||||
int getSize() const { return _size; }
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const VoxelColorDataPointer& reference);
|
||||
|
||||
private:
|
||||
|
||||
void read(Bitstream& in, int bytes);
|
||||
|
||||
QVector<QRgb> _contents;
|
||||
int _size;
|
||||
};
|
||||
|
||||
/// An attribute that stores voxel colors.
|
||||
class VoxelColorAttribute : public InlineAttribute<VoxelColorDataPointer> {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE VoxelColorAttribute(const QString& name = QString());
|
||||
|
||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
||||
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
|
||||
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
|
||||
|
||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<VoxelMaterialData> VoxelMaterialDataPointer;
|
||||
|
||||
/// Contains a block of voxel material data.
|
||||
class VoxelMaterialData : public DataBlock {
|
||||
public:
|
||||
|
||||
VoxelMaterialData(const QByteArray& contents, int size,
|
||||
const QVector<SharedObjectPointer>& materials = QVector<SharedObjectPointer>());
|
||||
VoxelMaterialData(Bitstream& in, int bytes);
|
||||
VoxelMaterialData(Bitstream& in, int bytes, const VoxelMaterialDataPointer& reference);
|
||||
|
||||
const QByteArray& getContents() const { return _contents; }
|
||||
|
||||
int getSize() const { return _size; }
|
||||
|
||||
const QVector<SharedObjectPointer>& getMaterials() const { return _materials; }
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const VoxelMaterialDataPointer& reference);
|
||||
|
||||
private:
|
||||
|
||||
void read(Bitstream& in, int bytes);
|
||||
|
||||
QByteArray _contents;
|
||||
int _size;
|
||||
QVector<SharedObjectPointer> _materials;
|
||||
};
|
||||
|
||||
/// An attribute that stores voxel materials.
|
||||
class VoxelMaterialAttribute : public InlineAttribute<VoxelMaterialDataPointer> {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE VoxelMaterialAttribute(const QString& name = QString());
|
||||
|
||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
||||
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
|
||||
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
|
||||
|
||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<VoxelHermiteData> VoxelHermiteDataPointer;
|
||||
|
||||
/// Contains a block of voxel Hermite data (positions and normals at edge crossings).
|
||||
class VoxelHermiteData : public DataBlock {
|
||||
public:
|
||||
|
||||
static const int EDGE_COUNT = 3;
|
||||
|
||||
VoxelHermiteData(const QVector<QRgb>& contents, int size);
|
||||
VoxelHermiteData(Bitstream& in, int bytes);
|
||||
VoxelHermiteData(Bitstream& in, int bytes, const VoxelHermiteDataPointer& reference);
|
||||
|
||||
const QVector<QRgb>& getContents() const { return _contents; }
|
||||
|
||||
int getSize() const { return _size; }
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const VoxelHermiteDataPointer& reference);
|
||||
|
||||
private:
|
||||
|
||||
void read(Bitstream& in, int bytes);
|
||||
|
||||
QVector<QRgb> _contents;
|
||||
int _size;
|
||||
};
|
||||
|
||||
/// An attribute that stores voxel Hermite data.
|
||||
class VoxelHermiteAttribute : public InlineAttribute<VoxelHermiteDataPointer> {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE VoxelHermiteAttribute(const QString& name = QString());
|
||||
|
||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
|
|
@ -414,119 +414,36 @@ PaintHeightfieldColorEdit::PaintHeightfieldColorEdit(const glm::vec3& position,
|
|||
color(color) {
|
||||
}
|
||||
|
||||
class PaintHeightfieldColorEditVisitor : public MetavoxelVisitor {
|
||||
class PaintHeightfieldMaterialEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit);
|
||||
PaintHeightfieldMaterialEditVisitor(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& material, const QColor& color);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
PaintHeightfieldColorEdit _edit;
|
||||
glm::vec3 _position;
|
||||
float _radius;
|
||||
SharedObjectPointer _material;
|
||||
QColor _color;
|
||||
Box _bounds;
|
||||
};
|
||||
|
||||
PaintHeightfieldColorEditVisitor::PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute(),
|
||||
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute()),
|
||||
_edit(edit) {
|
||||
PaintHeightfieldMaterialEditVisitor::PaintHeightfieldMaterialEditVisitor(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& material, const QColor& color) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute(), QVector<AttributePointer>() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute()),
|
||||
_position(position),
|
||||
_radius(radius),
|
||||
_material(material),
|
||||
_color(color) {
|
||||
|
||||
glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
|
||||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||
}
|
||||
|
||||
static void paintColor(MetavoxelInfo& info, int index, const glm::vec3& position, float radius, const QColor& color) {
|
||||
HeightfieldColorDataPointer pointer = info.inputValues.at(index).getInlineValue<HeightfieldColorDataPointer>();
|
||||
if (!pointer) {
|
||||
return;
|
||||
}
|
||||
QByteArray contents(pointer->getContents());
|
||||
int size = glm::sqrt((float)contents.size() / HeightfieldData::COLOR_BYTES);
|
||||
int highest = size - 1;
|
||||
float heightScale = size / info.size;
|
||||
|
||||
glm::vec3 center = (position - info.minimum) * heightScale;
|
||||
float scaledRadius = radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// paint all points within the radius
|
||||
float z = qMax(start.z, 0.0f);
|
||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||
int stride = size * HeightfieldData::COLOR_BYTES;
|
||||
char* lineDest = contents.data() + (int)z * stride + (int)startX * HeightfieldData::COLOR_BYTES;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
char red = color.red(), green = color.green(), blue = color.blue();
|
||||
bool changed = false;
|
||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||
char* dest = lineDest;
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest += HeightfieldData::COLOR_BYTES) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
if (dx * dx + dz * dz <= squaredRadius) {
|
||||
dest[0] = red;
|
||||
dest[1] = green;
|
||||
dest[2] = blue;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
lineDest += stride;
|
||||
}
|
||||
if (changed) {
|
||||
HeightfieldColorDataPointer newPointer(new HeightfieldColorData(contents));
|
||||
info.outputValues[index] = AttributeValue(info.inputValues.at(index).getAttribute(),
|
||||
encodeInline<HeightfieldColorDataPointer>(newPointer));
|
||||
}
|
||||
}
|
||||
|
||||
int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.getBounds().intersects(_bounds)) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (!info.isLeaf) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
paintColor(info, 0, _edit.position, _edit.radius, _edit.color);
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
void PaintHeightfieldColorEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
PaintHeightfieldColorEditVisitor visitor(*this);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
PaintHeightfieldTextureEdit::PaintHeightfieldTextureEdit(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& texture, const QColor& averageColor) :
|
||||
position(position),
|
||||
radius(radius),
|
||||
texture(texture),
|
||||
averageColor(averageColor) {
|
||||
}
|
||||
|
||||
class PaintHeightfieldTextureEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
PaintHeightfieldTextureEditVisitor(const PaintHeightfieldTextureEdit& edit);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
PaintHeightfieldTextureEdit _edit;
|
||||
Box _bounds;
|
||||
};
|
||||
|
||||
PaintHeightfieldTextureEditVisitor::PaintHeightfieldTextureEditVisitor(const PaintHeightfieldTextureEdit& edit) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldTextureAttribute() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector<AttributePointer>() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldTextureAttribute() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute()),
|
||||
_edit(edit) {
|
||||
|
||||
glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
|
||||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||
glm::vec3 extents(_radius, _radius, _radius);
|
||||
_bounds = Box(_position - extents, _position + extents);
|
||||
}
|
||||
|
||||
static QHash<uchar, int> countIndices(const QByteArray& contents) {
|
||||
|
@ -539,106 +456,624 @@ static QHash<uchar, int> countIndices(const QByteArray& contents) {
|
|||
return counts;
|
||||
}
|
||||
|
||||
int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) {
|
||||
uchar getMaterialIndex(const SharedObjectPointer& material, QVector<SharedObjectPointer>& materials, QByteArray& contents) {
|
||||
if (!(material && static_cast<MaterialObject*>(material.data())->getDiffuse().isValid())) {
|
||||
return 0;
|
||||
}
|
||||
// first look for a matching existing material, noting the first reusable slot
|
||||
int firstEmptyIndex = -1;
|
||||
for (int i = 0; i < materials.size(); i++) {
|
||||
const SharedObjectPointer& existingMaterial = materials.at(i);
|
||||
if (existingMaterial) {
|
||||
if (existingMaterial->equals(material.data())) {
|
||||
return i + 1;
|
||||
}
|
||||
} else if (firstEmptyIndex == -1) {
|
||||
firstEmptyIndex = i;
|
||||
}
|
||||
}
|
||||
// if nothing found, use the first empty slot or append
|
||||
if (firstEmptyIndex != -1) {
|
||||
materials[firstEmptyIndex] = material;
|
||||
return firstEmptyIndex + 1;
|
||||
}
|
||||
if (materials.size() < EIGHT_BIT_MAXIMUM) {
|
||||
materials.append(material);
|
||||
return materials.size();
|
||||
}
|
||||
// last resort: find the least-used material and remove it
|
||||
QHash<uchar, int> counts = countIndices(contents);
|
||||
uchar materialIndex = 0;
|
||||
int lowestCount = INT_MAX;
|
||||
for (QHash<uchar, int>::const_iterator it = counts.constBegin(); it != counts.constEnd(); it++) {
|
||||
if (it.value() < lowestCount) {
|
||||
materialIndex = it.key();
|
||||
lowestCount = it.value();
|
||||
}
|
||||
}
|
||||
contents.replace((char)materialIndex, (char)0);
|
||||
return materialIndex;
|
||||
}
|
||||
|
||||
void clearUnusedMaterials(QVector<SharedObjectPointer>& materials, QByteArray& contents) {
|
||||
QHash<uchar, int> counts = countIndices(contents);
|
||||
for (int i = 0; i < materials.size(); i++) {
|
||||
if (counts.value(i + 1) == 0) {
|
||||
materials[i] = SharedObjectPointer();
|
||||
}
|
||||
}
|
||||
while (!(materials.isEmpty() || materials.last())) {
|
||||
materials.removeLast();
|
||||
}
|
||||
}
|
||||
|
||||
int PaintHeightfieldMaterialEditVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.getBounds().intersects(_bounds)) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (!info.isLeaf) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
HeightfieldTextureDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldTextureDataPointer>();
|
||||
if (!pointer) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
QVector<SharedObjectPointer> textures = pointer->getTextures();
|
||||
QByteArray contents(pointer->getContents());
|
||||
uchar textureIndex = 0;
|
||||
if (_edit.texture && static_cast<HeightfieldTexture*>(_edit.texture.data())->getURL().isValid()) {
|
||||
// first look for a matching existing texture, noting the first reusable slot
|
||||
int firstEmptyIndex = -1;
|
||||
for (int i = 0; i < textures.size(); i++) {
|
||||
const SharedObjectPointer& texture = textures.at(i);
|
||||
if (texture) {
|
||||
if (texture->equals(_edit.texture.data())) {
|
||||
textureIndex = i + 1;
|
||||
break;
|
||||
HeightfieldColorDataPointer colorPointer = info.inputValues.at(0).getInlineValue<HeightfieldColorDataPointer>();
|
||||
if (colorPointer) {
|
||||
QByteArray contents(colorPointer->getContents());
|
||||
int size = glm::sqrt((float)contents.size() / DataBlock::COLOR_BYTES);
|
||||
int highest = size - 1;
|
||||
float heightScale = size / info.size;
|
||||
|
||||
glm::vec3 center = (_position - info.minimum) * heightScale;
|
||||
float scaledRadius = _radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// paint all points within the radius
|
||||
float z = qMax(start.z, 0.0f);
|
||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||
int stride = size * DataBlock::COLOR_BYTES;
|
||||
char* lineDest = contents.data() + (int)z * stride + (int)startX * DataBlock::COLOR_BYTES;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
char red = _color.red(), green = _color.green(), blue = _color.blue();
|
||||
bool changed = false;
|
||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||
char* dest = lineDest;
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest += DataBlock::COLOR_BYTES) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
if (dx * dx + dz * dz <= squaredRadius) {
|
||||
dest[0] = red;
|
||||
dest[1] = green;
|
||||
dest[2] = blue;
|
||||
changed = true;
|
||||
}
|
||||
} else if (firstEmptyIndex == -1) {
|
||||
firstEmptyIndex = i;
|
||||
}
|
||||
lineDest += stride;
|
||||
}
|
||||
// if nothing found, use the first empty slot or append
|
||||
if (textureIndex == 0) {
|
||||
if (firstEmptyIndex != -1) {
|
||||
textures[firstEmptyIndex] = _edit.texture;
|
||||
textureIndex = firstEmptyIndex + 1;
|
||||
|
||||
} else if (textures.size() < EIGHT_BIT_MAXIMUM) {
|
||||
textures.append(_edit.texture);
|
||||
textureIndex = textures.size();
|
||||
|
||||
} else {
|
||||
// last resort: find the least-used texture and remove it
|
||||
QHash<uchar, int> counts = countIndices(contents);
|
||||
int lowestCount = INT_MAX;
|
||||
for (QHash<uchar, int>::const_iterator it = counts.constBegin(); it != counts.constEnd(); it++) {
|
||||
if (it.value() < lowestCount) {
|
||||
textureIndex = it.key();
|
||||
lowestCount = it.value();
|
||||
}
|
||||
if (changed) {
|
||||
HeightfieldColorDataPointer newPointer(new HeightfieldColorData(contents));
|
||||
info.outputValues[0] = AttributeValue(info.inputValues.at(0).getAttribute(),
|
||||
encodeInline<HeightfieldColorDataPointer>(newPointer));
|
||||
}
|
||||
}
|
||||
|
||||
HeightfieldMaterialDataPointer materialPointer = info.inputValues.at(1).getInlineValue<HeightfieldMaterialDataPointer>();
|
||||
if (materialPointer) {
|
||||
QVector<SharedObjectPointer> materials = materialPointer->getMaterials();
|
||||
QByteArray contents(materialPointer->getContents());
|
||||
uchar materialIndex = getMaterialIndex(_material, materials, contents);
|
||||
int size = glm::sqrt((float)contents.size());
|
||||
int highest = size - 1;
|
||||
float heightScale = highest / info.size;
|
||||
|
||||
glm::vec3 center = (_position - info.minimum) * heightScale;
|
||||
float scaledRadius = _radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// paint all points within the radius
|
||||
float z = qMax(start.z, 0.0f);
|
||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||
uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
bool changed = false;
|
||||
QHash<uchar, int> counts;
|
||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||
uchar* dest = lineDest;
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
if (dx * dx + dz * dz <= squaredRadius) {
|
||||
*dest = materialIndex;
|
||||
changed = true;
|
||||
}
|
||||
contents.replace((char)textureIndex, (char)0);
|
||||
}
|
||||
lineDest += size;
|
||||
}
|
||||
if (changed) {
|
||||
clearUnusedMaterials(materials, contents);
|
||||
HeightfieldMaterialDataPointer newPointer(new HeightfieldMaterialData(contents, materials));
|
||||
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<HeightfieldMaterialDataPointer>(newPointer));
|
||||
}
|
||||
}
|
||||
int size = glm::sqrt((float)contents.size());
|
||||
int highest = size - 1;
|
||||
float heightScale = highest / info.size;
|
||||
|
||||
glm::vec3 center = (_edit.position - info.minimum) * heightScale;
|
||||
float scaledRadius = _edit.radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// paint all points within the radius
|
||||
float z = qMax(start.z, 0.0f);
|
||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||
uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
bool changed = false;
|
||||
QHash<uchar, int> counts;
|
||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||
uchar* dest = lineDest;
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
if (dx * dx + dz * dz <= squaredRadius) {
|
||||
*dest = textureIndex;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
lineDest += size;
|
||||
}
|
||||
if (changed) {
|
||||
// clear any unused textures
|
||||
QHash<uchar, int> counts = countIndices(contents);
|
||||
for (int i = 0; i < textures.size(); i++) {
|
||||
if (counts.value(i + 1) == 0) {
|
||||
textures[i] = SharedObjectPointer();
|
||||
}
|
||||
}
|
||||
while (!(textures.isEmpty() || textures.last())) {
|
||||
textures.removeLast();
|
||||
}
|
||||
HeightfieldTextureDataPointer newPointer(new HeightfieldTextureData(contents, textures));
|
||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldTextureDataPointer>(newPointer));
|
||||
}
|
||||
paintColor(info, 1, _edit.position, _edit.radius, _edit.averageColor);
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
void PaintHeightfieldTextureEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
PaintHeightfieldTextureEditVisitor visitor(*this);
|
||||
void PaintHeightfieldColorEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
PaintHeightfieldMaterialEditVisitor visitor(position, radius, SharedObjectPointer(), color);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
position(position),
|
||||
radius(radius),
|
||||
material(material),
|
||||
averageColor(averageColor) {
|
||||
}
|
||||
|
||||
void PaintHeightfieldMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
PaintHeightfieldMaterialEditVisitor visitor(position, radius, material, averageColor);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
VoxelColorBoxEdit::VoxelColorBoxEdit(const Box& region, float granularity, const QColor& color) :
|
||||
region(region),
|
||||
granularity(granularity),
|
||||
color(color) {
|
||||
}
|
||||
|
||||
const int VOXEL_BLOCK_SIZE = 16;
|
||||
const int VOXEL_BLOCK_SAMPLES = VOXEL_BLOCK_SIZE + 1;
|
||||
const int VOXEL_BLOCK_AREA = VOXEL_BLOCK_SAMPLES * VOXEL_BLOCK_SAMPLES;
|
||||
const int VOXEL_BLOCK_VOLUME = VOXEL_BLOCK_AREA * VOXEL_BLOCK_SAMPLES;
|
||||
|
||||
class VoxelMaterialBoxEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
VoxelMaterialBoxEditVisitor(const Box& region, float granularity,
|
||||
const SharedObjectPointer& material, const QColor& color);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
Box _region;
|
||||
SharedObjectPointer _material;
|
||||
QColor _color;
|
||||
float _blockSize;
|
||||
};
|
||||
|
||||
VoxelMaterialBoxEditVisitor::VoxelMaterialBoxEditVisitor(const Box& region, float granularity,
|
||||
const SharedObjectPointer& material, const QColor& color) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getVoxelColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelHermiteAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelMaterialAttribute(), QVector<AttributePointer>() <<
|
||||
AttributeRegistry::getInstance()->getVoxelColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelHermiteAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelMaterialAttribute()),
|
||||
_region(region),
|
||||
_material(material),
|
||||
_color(color),
|
||||
_blockSize(granularity * VOXEL_BLOCK_SIZE) {
|
||||
}
|
||||
|
||||
int VoxelMaterialBoxEditVisitor::visit(MetavoxelInfo& info) {
|
||||
Box bounds = info.getBounds();
|
||||
if (!bounds.intersects(_region)) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (info.size > _blockSize) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
VoxelColorDataPointer colorPointer = info.inputValues.at(0).getInlineValue<VoxelColorDataPointer>();
|
||||
QVector<QRgb> colorContents = (colorPointer && colorPointer->getSize() == VOXEL_BLOCK_SAMPLES) ?
|
||||
colorPointer->getContents() : QVector<QRgb>(VOXEL_BLOCK_VOLUME);
|
||||
|
||||
Box overlap = info.getBounds().getIntersection(_region);
|
||||
float scale = VOXEL_BLOCK_SIZE / info.size;
|
||||
overlap.minimum = (overlap.minimum - info.minimum) * scale;
|
||||
overlap.maximum = (overlap.maximum - info.minimum) * scale;
|
||||
int minX = glm::ceil(overlap.minimum.x);
|
||||
int minY = glm::ceil(overlap.minimum.y);
|
||||
int minZ = glm::ceil(overlap.minimum.z);
|
||||
int sizeX = (int)overlap.maximum.x - minX + 1;
|
||||
int sizeY = (int)overlap.maximum.y - minY + 1;
|
||||
int sizeZ = (int)overlap.maximum.z - minZ + 1;
|
||||
|
||||
QRgb rgb = _color.rgba();
|
||||
for (QRgb* destZ = colorContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
|
||||
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA) {
|
||||
for (QRgb* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY; destY += VOXEL_BLOCK_SAMPLES) {
|
||||
for (QRgb* destX = destY, *endX = destX + sizeX; destX != endX; destX++) {
|
||||
*destX = rgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoxelColorDataPointer newColorPointer(new VoxelColorData(colorContents, VOXEL_BLOCK_SAMPLES));
|
||||
info.outputValues[0] = AttributeValue(info.inputValues.at(0).getAttribute(),
|
||||
encodeInline<VoxelColorDataPointer>(newColorPointer));
|
||||
|
||||
VoxelHermiteDataPointer hermitePointer = info.inputValues.at(1).getInlineValue<VoxelHermiteDataPointer>();
|
||||
QVector<QRgb> hermiteContents = (hermitePointer && hermitePointer->getSize() == VOXEL_BLOCK_SAMPLES) ?
|
||||
hermitePointer->getContents() : QVector<QRgb>(VOXEL_BLOCK_VOLUME * VoxelHermiteData::EDGE_COUNT);
|
||||
int hermiteArea = VOXEL_BLOCK_AREA * VoxelHermiteData::EDGE_COUNT;
|
||||
int hermiteSamples = VOXEL_BLOCK_SAMPLES * VoxelHermiteData::EDGE_COUNT;
|
||||
|
||||
int hermiteMinX = minX, hermiteMinY = minY, hermiteMinZ = minZ;
|
||||
int hermiteSizeX = sizeX, hermiteSizeY = sizeY, hermiteSizeZ = sizeZ;
|
||||
if (minX > 0) {
|
||||
hermiteMinX--;
|
||||
hermiteSizeX++;
|
||||
}
|
||||
if (minY > 0) {
|
||||
hermiteMinY--;
|
||||
hermiteSizeY++;
|
||||
}
|
||||
if (minZ > 0) {
|
||||
hermiteMinZ--;
|
||||
hermiteSizeZ++;
|
||||
}
|
||||
const int NORMAL_MAX = 127;
|
||||
QRgb* hermiteDestZ = hermiteContents.data() + hermiteMinZ * hermiteArea + hermiteMinY * hermiteSamples +
|
||||
hermiteMinX * VoxelHermiteData::EDGE_COUNT;
|
||||
for (int z = hermiteMinZ, hermiteMaxZ = z + hermiteSizeZ - 1; z <= hermiteMaxZ; z++, hermiteDestZ += hermiteArea) {
|
||||
QRgb* hermiteDestY = hermiteDestZ;
|
||||
for (int y = hermiteMinY, hermiteMaxY = y + hermiteSizeY - 1; y <= hermiteMaxY; y++, hermiteDestY += hermiteSamples) {
|
||||
QRgb* hermiteDestX = hermiteDestY;
|
||||
for (int x = hermiteMinX, hermiteMaxX = x + hermiteSizeX - 1; x <= hermiteMaxX; x++,
|
||||
hermiteDestX += VoxelHermiteData::EDGE_COUNT) {
|
||||
// internal edges are set to zero; border edges (when non-terminal) are set to the intersection values
|
||||
hermiteDestX[0] = 0x0;
|
||||
if ((x == hermiteMinX || x == hermiteMaxX) && x != VOXEL_BLOCK_SIZE) {
|
||||
const QRgb* color = colorContents.constData() + z * VOXEL_BLOCK_AREA + y * VOXEL_BLOCK_SAMPLES + x;
|
||||
int alpha0 = qAlpha(color[0]);
|
||||
if (alpha0 != qAlpha(color[1])) {
|
||||
hermiteDestX[0] = qRgba(alpha0 == 0 ? -NORMAL_MAX : NORMAL_MAX, 0, 0,
|
||||
((x == hermiteMinX ? overlap.minimum.x : overlap.maximum.x) - x) * EIGHT_BIT_MAXIMUM);
|
||||
}
|
||||
}
|
||||
hermiteDestX[1] = 0x0;
|
||||
if ((y == hermiteMinY || y == hermiteMaxY) && y != VOXEL_BLOCK_SIZE) {
|
||||
const QRgb* color = colorContents.constData() + z * VOXEL_BLOCK_AREA + y * VOXEL_BLOCK_SAMPLES + x;
|
||||
int alpha0 = qAlpha(color[0]);
|
||||
if (alpha0 != qAlpha(color[VOXEL_BLOCK_SAMPLES])) {
|
||||
hermiteDestX[1] = qRgba(0, alpha0 == 0 ? -NORMAL_MAX : NORMAL_MAX, 0,
|
||||
((y == hermiteMinY ? overlap.minimum.y : overlap.maximum.y) - y) * EIGHT_BIT_MAXIMUM);
|
||||
}
|
||||
}
|
||||
hermiteDestX[2] = 0x0;
|
||||
if ((z == hermiteMinZ || z == hermiteMaxZ) && z != VOXEL_BLOCK_SIZE) {
|
||||
const QRgb* color = colorContents.constData() + z * VOXEL_BLOCK_AREA + y * VOXEL_BLOCK_SAMPLES + x;
|
||||
int alpha0 = qAlpha(color[0]);
|
||||
if (alpha0 != qAlpha(color[VOXEL_BLOCK_AREA])) {
|
||||
hermiteDestX[2] = qRgba(0, 0, alpha0 == 0 ? -NORMAL_MAX : NORMAL_MAX,
|
||||
((z == hermiteMinZ ? overlap.minimum.z : overlap.maximum.z) - z) * EIGHT_BIT_MAXIMUM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoxelHermiteDataPointer newHermitePointer(new VoxelHermiteData(hermiteContents, VOXEL_BLOCK_SAMPLES));
|
||||
info.outputValues[1] = AttributeValue(info.inputValues.at(1).getAttribute(),
|
||||
encodeInline<VoxelHermiteDataPointer>(newHermitePointer));
|
||||
|
||||
VoxelMaterialDataPointer materialPointer = info.inputValues.at(2).getInlineValue<VoxelMaterialDataPointer>();
|
||||
QByteArray materialContents;
|
||||
QVector<SharedObjectPointer> materials;
|
||||
if (materialPointer && materialPointer->getSize() == VOXEL_BLOCK_SAMPLES) {
|
||||
materialContents = materialPointer->getContents();
|
||||
materials = materialPointer->getMaterials();
|
||||
|
||||
} else {
|
||||
materialContents = QByteArray(VOXEL_BLOCK_VOLUME, 0);
|
||||
}
|
||||
|
||||
uchar materialIndex = getMaterialIndex(_material, materials, materialContents);
|
||||
for (uchar* destZ = (uchar*)materialContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
|
||||
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA) {
|
||||
for (uchar* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY; destY += VOXEL_BLOCK_SAMPLES) {
|
||||
for (uchar* destX = destY, *endX = destX + sizeX; destX != endX; destX++) {
|
||||
*destX = materialIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearUnusedMaterials(materials, materialContents);
|
||||
VoxelMaterialDataPointer newMaterialPointer(new VoxelMaterialData(materialContents, VOXEL_BLOCK_SAMPLES, materials));
|
||||
info.outputValues[2] = AttributeValue(_inputs.at(2), encodeInline<VoxelMaterialDataPointer>(newMaterialPointer));
|
||||
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
void VoxelColorBoxEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
// expand to fit the entire edit
|
||||
while (!data.getBounds().contains(region)) {
|
||||
data.expand();
|
||||
}
|
||||
VoxelMaterialBoxEditVisitor visitor(region, granularity, SharedObjectPointer(), color);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
VoxelMaterialBoxEdit::VoxelMaterialBoxEdit(const Box& region, float granularity,
|
||||
const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
region(region),
|
||||
granularity(granularity),
|
||||
material(material),
|
||||
averageColor(averageColor) {
|
||||
}
|
||||
|
||||
void VoxelMaterialBoxEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
// expand to fit the entire edit
|
||||
while (!data.getBounds().contains(region)) {
|
||||
data.expand();
|
||||
}
|
||||
VoxelMaterialBoxEditVisitor visitor(region, granularity, material, averageColor);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
VoxelColorSphereEdit::VoxelColorSphereEdit(const glm::vec3& center, float radius, float granularity, const QColor& color) :
|
||||
center(center),
|
||||
radius(radius),
|
||||
granularity(granularity),
|
||||
color(color) {
|
||||
}
|
||||
|
||||
class VoxelMaterialSphereEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
VoxelMaterialSphereEditVisitor(const glm::vec3& center, float radius, const Box& bounds, float granularity,
|
||||
const SharedObjectPointer& material, const QColor& color);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
glm::vec3 _center;
|
||||
float _radius;
|
||||
Box _bounds;
|
||||
SharedObjectPointer _material;
|
||||
QColor _color;
|
||||
float _blockSize;
|
||||
};
|
||||
|
||||
VoxelMaterialSphereEditVisitor::VoxelMaterialSphereEditVisitor(const glm::vec3& center, float radius, const Box& bounds,
|
||||
float granularity, const SharedObjectPointer& material, const QColor& color) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getVoxelColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelHermiteAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelMaterialAttribute(), QVector<AttributePointer>() <<
|
||||
AttributeRegistry::getInstance()->getVoxelColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelHermiteAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelMaterialAttribute()),
|
||||
_center(center),
|
||||
_radius(radius),
|
||||
_bounds(bounds),
|
||||
_material(material),
|
||||
_color(color),
|
||||
_blockSize(granularity * VOXEL_BLOCK_SIZE) {
|
||||
}
|
||||
|
||||
int VoxelMaterialSphereEditVisitor::visit(MetavoxelInfo& info) {
|
||||
Box bounds = info.getBounds();
|
||||
if (!bounds.intersects(_bounds)) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (info.size > _blockSize) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
VoxelColorDataPointer colorPointer = info.inputValues.at(0).getInlineValue<VoxelColorDataPointer>();
|
||||
QVector<QRgb> colorContents = (colorPointer && colorPointer->getSize() == VOXEL_BLOCK_SAMPLES) ?
|
||||
colorPointer->getContents() : QVector<QRgb>(VOXEL_BLOCK_VOLUME);
|
||||
|
||||
Box overlap = info.getBounds().getIntersection(_bounds);
|
||||
float scale = VOXEL_BLOCK_SIZE / info.size;
|
||||
overlap.minimum = (overlap.minimum - info.minimum) * scale;
|
||||
overlap.maximum = (overlap.maximum - info.minimum) * scale;
|
||||
int minX = glm::ceil(overlap.minimum.x);
|
||||
int minY = glm::ceil(overlap.minimum.y);
|
||||
int minZ = glm::ceil(overlap.minimum.z);
|
||||
int sizeX = (int)overlap.maximum.x - minX + 1;
|
||||
int sizeY = (int)overlap.maximum.y - minY + 1;
|
||||
int sizeZ = (int)overlap.maximum.z - minZ + 1;
|
||||
|
||||
glm::vec3 relativeCenter = (_center - info.minimum) * scale;
|
||||
float relativeRadius = _radius * scale;
|
||||
float relativeRadiusSquared = relativeRadius * relativeRadius;
|
||||
|
||||
QRgb rgb = _color.rgba();
|
||||
glm::vec3 position(0.0f, 0.0f, minZ);
|
||||
for (QRgb* destZ = colorContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
|
||||
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA, position.z++) {
|
||||
position.y = minY;
|
||||
for (QRgb* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY;
|
||||
destY += VOXEL_BLOCK_SAMPLES, position.y++) {
|
||||
position.x = minX;
|
||||
for (QRgb* destX = destY, *endX = destX + sizeX; destX != endX; destX++, position.x++) {
|
||||
if (glm::distance(relativeCenter, position) <= relativeRadius) {
|
||||
*destX = rgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoxelColorDataPointer newColorPointer(new VoxelColorData(colorContents, VOXEL_BLOCK_SAMPLES));
|
||||
info.outputValues[0] = AttributeValue(info.inputValues.at(0).getAttribute(),
|
||||
encodeInline<VoxelColorDataPointer>(newColorPointer));
|
||||
|
||||
VoxelHermiteDataPointer hermitePointer = info.inputValues.at(1).getInlineValue<VoxelHermiteDataPointer>();
|
||||
QVector<QRgb> hermiteContents = (hermitePointer && hermitePointer->getSize() == VOXEL_BLOCK_SAMPLES) ?
|
||||
hermitePointer->getContents() : QVector<QRgb>(VOXEL_BLOCK_VOLUME * VoxelHermiteData::EDGE_COUNT);
|
||||
int hermiteArea = VOXEL_BLOCK_AREA * VoxelHermiteData::EDGE_COUNT;
|
||||
int hermiteSamples = VOXEL_BLOCK_SAMPLES * VoxelHermiteData::EDGE_COUNT;
|
||||
|
||||
int hermiteMinX = minX, hermiteMinY = minY, hermiteMinZ = minZ;
|
||||
int hermiteSizeX = sizeX, hermiteSizeY = sizeY, hermiteSizeZ = sizeZ;
|
||||
if (minX > 0) {
|
||||
hermiteMinX--;
|
||||
hermiteSizeX++;
|
||||
}
|
||||
if (minY > 0) {
|
||||
hermiteMinY--;
|
||||
hermiteSizeY++;
|
||||
}
|
||||
if (minZ > 0) {
|
||||
hermiteMinZ--;
|
||||
hermiteSizeZ++;
|
||||
}
|
||||
QRgb* hermiteDestZ = hermiteContents.data() + hermiteMinZ * hermiteArea + hermiteMinY * hermiteSamples +
|
||||
hermiteMinX * VoxelHermiteData::EDGE_COUNT;
|
||||
for (int z = hermiteMinZ, hermiteMaxZ = z + hermiteSizeZ - 1; z <= hermiteMaxZ; z++, hermiteDestZ += hermiteArea) {
|
||||
QRgb* hermiteDestY = hermiteDestZ;
|
||||
for (int y = hermiteMinY, hermiteMaxY = y + hermiteSizeY - 1; y <= hermiteMaxY; y++, hermiteDestY += hermiteSamples) {
|
||||
QRgb* hermiteDestX = hermiteDestY;
|
||||
for (int x = hermiteMinX, hermiteMaxX = x + hermiteSizeX - 1; x <= hermiteMaxX; x++,
|
||||
hermiteDestX += VoxelHermiteData::EDGE_COUNT) {
|
||||
// at each intersected non-terminal edge, we check for a transition and, if one is detected, we assign the
|
||||
// crossing and normal values based on intersection with the sphere
|
||||
hermiteDestX[0] = 0x0;
|
||||
glm::vec3 offset(x - relativeCenter.x, y - relativeCenter.y, z - relativeCenter.z);
|
||||
if (x != VOXEL_BLOCK_SIZE) {
|
||||
const QRgb* color = colorContents.constData() + z * VOXEL_BLOCK_AREA + y * VOXEL_BLOCK_SAMPLES + x;
|
||||
int alpha0 = qAlpha(color[0]);
|
||||
if (alpha0 != qAlpha(color[1])) {
|
||||
float radicand = relativeRadiusSquared - offset.y * offset.y - offset.z * offset.z;
|
||||
float parameter = 0.5f;
|
||||
if (radicand >= 0.0f) {
|
||||
float root = glm::sqrt(radicand);
|
||||
parameter = -offset.x - root;
|
||||
if (parameter < 0.0f || parameter > 1.0f) {
|
||||
parameter = glm::clamp(-offset.x + root, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
glm::vec3 normal = offset + glm::vec3(parameter, 0.0f, 0.0f);
|
||||
float length = glm::length(normal);
|
||||
if (length > EPSILON) {
|
||||
normal /= length;
|
||||
} else {
|
||||
normal = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
hermiteDestX[0] = packNormal(normal, parameter * EIGHT_BIT_MAXIMUM);
|
||||
}
|
||||
}
|
||||
hermiteDestX[1] = 0x0;
|
||||
if (y != VOXEL_BLOCK_SIZE) {
|
||||
const QRgb* color = colorContents.constData() + z * VOXEL_BLOCK_AREA + y * VOXEL_BLOCK_SAMPLES + x;
|
||||
int alpha0 = qAlpha(color[0]);
|
||||
if (alpha0 != qAlpha(color[VOXEL_BLOCK_SAMPLES])) {
|
||||
float radicand = relativeRadiusSquared - offset.x * offset.x - offset.z * offset.z;
|
||||
float parameter = 0.5f;
|
||||
if (radicand >= 0.0f) {
|
||||
float root = glm::sqrt(radicand);
|
||||
parameter = -offset.y - root;
|
||||
if (parameter < 0.0f || parameter > 1.0f) {
|
||||
parameter = glm::clamp(-offset.y + root, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
glm::vec3 normal = offset + glm::vec3(parameter, 0.0f, 0.0f);
|
||||
float length = glm::length(normal);
|
||||
if (length > EPSILON) {
|
||||
normal /= length;
|
||||
} else {
|
||||
normal = glm::vec3(1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
hermiteDestX[1] = packNormal(normal, parameter * EIGHT_BIT_MAXIMUM);
|
||||
}
|
||||
}
|
||||
hermiteDestX[2] = 0x0;
|
||||
if (z != VOXEL_BLOCK_SIZE) {
|
||||
const QRgb* color = colorContents.constData() + z * VOXEL_BLOCK_AREA + y * VOXEL_BLOCK_SAMPLES + x;
|
||||
int alpha0 = qAlpha(color[0]);
|
||||
if (alpha0 != qAlpha(color[VOXEL_BLOCK_AREA])) {
|
||||
float radicand = relativeRadiusSquared - offset.x * offset.x - offset.y * offset.y;
|
||||
float parameter = 0.5f;
|
||||
if (radicand >= 0.0f) {
|
||||
float root = glm::sqrt(radicand);
|
||||
parameter = -offset.z - root;
|
||||
if (parameter < 0.0f || parameter > 1.0f) {
|
||||
parameter = glm::clamp(-offset.z + root, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
glm::vec3 normal = offset + glm::vec3(parameter, 0.0f, 0.0f);
|
||||
float length = glm::length(normal);
|
||||
if (length > EPSILON) {
|
||||
normal /= length;
|
||||
} else {
|
||||
normal = glm::vec3(1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
hermiteDestX[2] = packNormal(normal, parameter * EIGHT_BIT_MAXIMUM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoxelHermiteDataPointer newHermitePointer(new VoxelHermiteData(hermiteContents, VOXEL_BLOCK_SAMPLES));
|
||||
info.outputValues[1] = AttributeValue(info.inputValues.at(1).getAttribute(),
|
||||
encodeInline<VoxelHermiteDataPointer>(newHermitePointer));
|
||||
|
||||
VoxelMaterialDataPointer materialPointer = info.inputValues.at(2).getInlineValue<VoxelMaterialDataPointer>();
|
||||
QByteArray materialContents;
|
||||
QVector<SharedObjectPointer> materials;
|
||||
if (materialPointer && materialPointer->getSize() == VOXEL_BLOCK_SAMPLES) {
|
||||
materialContents = materialPointer->getContents();
|
||||
materials = materialPointer->getMaterials();
|
||||
|
||||
} else {
|
||||
materialContents = QByteArray(VOXEL_BLOCK_VOLUME, 0);
|
||||
}
|
||||
|
||||
uchar materialIndex = getMaterialIndex(_material, materials, materialContents);
|
||||
position.z = minZ;
|
||||
for (uchar* destZ = (uchar*)materialContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
|
||||
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA, position.z++) {
|
||||
position.y = minY;
|
||||
for (uchar* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY;
|
||||
destY += VOXEL_BLOCK_SAMPLES, position.y++) {
|
||||
position.x = minX;
|
||||
for (uchar* destX = destY, *endX = destX + sizeX; destX != endX; destX++, position.x++) {
|
||||
if (glm::distance(relativeCenter, position) <= relativeRadius) {
|
||||
*destX = materialIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearUnusedMaterials(materials, materialContents);
|
||||
VoxelMaterialDataPointer newMaterialPointer(new VoxelMaterialData(materialContents, VOXEL_BLOCK_SAMPLES, materials));
|
||||
info.outputValues[2] = AttributeValue(_inputs.at(2), encodeInline<VoxelMaterialDataPointer>(newMaterialPointer));
|
||||
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
void VoxelColorSphereEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
// expand to fit the entire edit
|
||||
glm::vec3 extents(radius, radius, radius);
|
||||
Box bounds(center - extents, center + extents);
|
||||
while (!data.getBounds().contains(bounds)) {
|
||||
data.expand();
|
||||
}
|
||||
VoxelMaterialSphereEditVisitor visitor(center, radius, bounds, granularity, SharedObjectPointer(), color);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
VoxelMaterialSphereEdit::VoxelMaterialSphereEdit(const glm::vec3& center, float radius, float granularity,
|
||||
const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
center(center),
|
||||
radius(radius),
|
||||
granularity(granularity),
|
||||
material(material),
|
||||
averageColor(averageColor) {
|
||||
}
|
||||
|
||||
void VoxelMaterialSphereEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
// expand to fit the entire edit
|
||||
glm::vec3 extents(radius, radius, radius);
|
||||
Box bounds(center - extents, center + extents);
|
||||
while (!data.getBounds().contains(bounds)) {
|
||||
data.expand();
|
||||
}
|
||||
VoxelMaterialSphereEditVisitor visitor(center, radius, bounds, granularity, material, averageColor);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
|
|
@ -241,23 +241,98 @@ public:
|
|||
|
||||
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldColorEdit)
|
||||
|
||||
/// An edit that sets a region of a heightfield texture.
|
||||
class PaintHeightfieldTextureEdit : public MetavoxelEdit {
|
||||
/// An edit that sets a region of a heightfield material.
|
||||
class PaintHeightfieldMaterialEdit : public MetavoxelEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM glm::vec3 position;
|
||||
STREAM float radius;
|
||||
STREAM SharedObjectPointer texture;
|
||||
STREAM SharedObjectPointer material;
|
||||
STREAM QColor averageColor;
|
||||
|
||||
PaintHeightfieldTextureEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f,
|
||||
const SharedObjectPointer& texture = SharedObjectPointer(), const QColor& averageColor = QColor());
|
||||
PaintHeightfieldMaterialEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f,
|
||||
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
|
||||
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldTextureEdit)
|
||||
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldMaterialEdit)
|
||||
|
||||
/// An edit that sets the color of voxels within a box to a value.
|
||||
class VoxelColorBoxEdit : public MetavoxelEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM Box region;
|
||||
STREAM float granularity;
|
||||
STREAM QColor color;
|
||||
|
||||
VoxelColorBoxEdit(const Box& region = Box(), float granularity = 0.0f, const QColor& color = QColor());
|
||||
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(VoxelColorBoxEdit)
|
||||
|
||||
/// An edit that sets the materials of voxels within a box to a value.
|
||||
class VoxelMaterialBoxEdit : public MetavoxelEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM Box region;
|
||||
STREAM float granularity;
|
||||
STREAM SharedObjectPointer material;
|
||||
STREAM QColor averageColor;
|
||||
|
||||
VoxelMaterialBoxEdit(const Box& region = Box(), float granularity = 0.0f,
|
||||
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
|
||||
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(VoxelMaterialBoxEdit)
|
||||
|
||||
/// An edit that sets the color of voxels within a sphere to a value.
|
||||
class VoxelColorSphereEdit : public MetavoxelEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM glm::vec3 center;
|
||||
STREAM float radius;
|
||||
STREAM float granularity;
|
||||
STREAM QColor color;
|
||||
|
||||
VoxelColorSphereEdit(const glm::vec3& center = glm::vec3(), float radius = 0.0f,
|
||||
float granularity = 0.0f, const QColor& color = QColor());
|
||||
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(VoxelColorSphereEdit)
|
||||
|
||||
/// An edit that sets the materials of voxels within a sphere to a value.
|
||||
class VoxelMaterialSphereEdit : public MetavoxelEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM glm::vec3 center;
|
||||
STREAM float radius;
|
||||
STREAM float granularity;
|
||||
STREAM SharedObjectPointer material;
|
||||
STREAM QColor averageColor;
|
||||
|
||||
VoxelMaterialSphereEdit(const glm::vec3& center = glm::vec3(), float radius = 0.0f, float granularity = 0.0f,
|
||||
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
|
||||
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(VoxelMaterialSphereEdit)
|
||||
|
||||
#endif // hifi_MetavoxelMessages_h
|
||||
|
|
Loading…
Reference in a new issue