mirror of
https://github.com/lubosz/overte.git
synced 2025-08-27 18:05:48 +02:00
Merge branch 'master' into memcheck-fixes
This commit is contained in:
commit
740ccd3495
121 changed files with 1570 additions and 1003 deletions
|
@ -14,12 +14,16 @@ package io.highfidelity.hifiinterface;
|
|||
import android.content.Intent;
|
||||
import android.content.res.AssetManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Vibrator;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.WindowManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.qtproject.qt5.android.QtLayout;
|
||||
import org.qtproject.qt5.android.QtSurface;
|
||||
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||
|
||||
/*import com.google.vr.cardboard.DisplaySynchronizer;
|
||||
|
@ -31,6 +35,9 @@ import android.content.pm.ActivityInfo;
|
|||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class InterfaceActivity extends QtActivity {
|
||||
|
||||
|
@ -134,6 +141,7 @@ public class InterfaceActivity extends QtActivity {
|
|||
protected void onResume() {
|
||||
super.onResume();
|
||||
nativeEnterForeground();
|
||||
surfacesWorkaround();
|
||||
//gvrApi.resumeTracking();
|
||||
}
|
||||
|
||||
|
@ -158,6 +166,41 @@ public class InterfaceActivity extends QtActivity {
|
|||
Log.w("[VR]", "Portrait detected but not in VR mode. Should not happen");
|
||||
}
|
||||
}
|
||||
surfacesWorkaround();
|
||||
}
|
||||
|
||||
private void surfacesWorkaround() {
|
||||
FrameLayout fl = findViewById(android.R.id.content);
|
||||
if (fl.getChildCount() > 0) {
|
||||
QtLayout qtLayout = (QtLayout) fl.getChildAt(0);
|
||||
if (qtLayout.getChildCount() > 1) {
|
||||
QtSurface s1 = (QtSurface) qtLayout.getChildAt(0);
|
||||
QtSurface s2 = (QtSurface) qtLayout.getChildAt(1);
|
||||
Integer subLayer1 = 0;
|
||||
Integer subLayer2 = 0;
|
||||
try {
|
||||
String field;
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
field = "mSubLayer";
|
||||
} else {
|
||||
field = "mWindowType";
|
||||
}
|
||||
Field f = s1.getClass().getSuperclass().getDeclaredField(field);
|
||||
f.setAccessible(true);
|
||||
subLayer1 = (Integer) f.get(s1);
|
||||
subLayer2 = (Integer) f.get(s2);
|
||||
if (subLayer1 < subLayer2) {
|
||||
s1.setVisibility(View.VISIBLE);
|
||||
s2.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
s1.setVisibility(View.INVISIBLE);
|
||||
s2.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Log.e(TAG, "Workaround failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void openUrlInAndroidWebView(String urlString) {
|
||||
|
|
|
@ -64,7 +64,11 @@ public class HomeFragment extends Fragment {
|
|||
mDomainsView.setLayoutManager(gridLayoutMgr);
|
||||
mDomainAdapter = new DomainAdapter(getContext(), HifiUtils.getInstance().protocolVersionSignature(), nativeGetLastLocation());
|
||||
mDomainAdapter.setClickListener((view, position, domain) -> {
|
||||
new Handler(getActivity().getMainLooper()).postDelayed(() -> mListener.onSelectedDomain(domain.url), 400); // a delay so the ripple effect can be seen
|
||||
new Handler(getActivity().getMainLooper()).postDelayed(() -> {
|
||||
if (mListener != null) {
|
||||
mListener.onSelectedDomain(domain.url);
|
||||
}
|
||||
}, 400); // a delay so the ripple effect can be seen
|
||||
});
|
||||
mDomainAdapter.setListener(new DomainAdapter.AdapterListener() {
|
||||
@Override
|
||||
|
@ -116,7 +120,9 @@ public class HomeFragment extends Fragment {
|
|||
if (!urlString.trim().isEmpty()) {
|
||||
urlString = HifiUtils.getInstance().sanitizeHifiUrl(urlString);
|
||||
}
|
||||
mListener.onSelectedDomain(urlString);
|
||||
if (mListener != null) {
|
||||
mListener.onSelectedDomain(urlString);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package io.highfidelity.hifiinterface.provider;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.MutableInt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import io.highfidelity.hifiinterface.HifiUtils;
|
||||
import io.highfidelity.hifiinterface.view.DomainAdapter;
|
||||
|
@ -47,24 +48,42 @@ public class UserStoryDomainProvider implements DomainProvider {
|
|||
suggestions = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void retrieve(String filterText, DomainCallback domainCallback) {
|
||||
if (!startedToGetFromAPI) {
|
||||
startedToGetFromAPI = true;
|
||||
fillDestinations(filterText, domainCallback);
|
||||
} else {
|
||||
filterChoicesByText(filterText, domainCallback);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillDestinations(String filterText, DomainCallback domainCallback) {
|
||||
StoriesFilter filter = new StoriesFilter(filterText);
|
||||
final MutableInt counter = new MutableInt(0);
|
||||
allStories.clear();
|
||||
getUserStoryPage(1,
|
||||
|
||||
List<UserStory> taggedStories = new ArrayList<>();
|
||||
Set<String> taggedStoriesIds = new HashSet<>();
|
||||
getUserStoryPage(1, taggedStories, TAGS_TO_SEARCH,
|
||||
e -> {
|
||||
allStories.subList(counter.value, allStories.size()).forEach(userStory -> {
|
||||
filter.filterOrAdd(userStory);
|
||||
});
|
||||
if (domainCallback != null) {
|
||||
domainCallback.retrieveOk(suggestions); //ended
|
||||
}
|
||||
},
|
||||
a -> {
|
||||
allStories.forEach(userStory -> {
|
||||
counter.value++;
|
||||
filter.filterOrAdd(userStory);
|
||||
taggedStories.forEach(userStory -> {
|
||||
taggedStoriesIds.add(userStory.id);
|
||||
});
|
||||
|
||||
allStories.clear();
|
||||
getUserStoryPage(1, allStories, null,
|
||||
ex -> {
|
||||
allStories.forEach(userStory -> {
|
||||
if (taggedStoriesIds.contains(userStory.id)) {
|
||||
userStory.tagFound = true;
|
||||
}
|
||||
filter.filterOrAdd(userStory);
|
||||
});
|
||||
if (domainCallback != null) {
|
||||
domainCallback.retrieveOk(suggestions); //ended
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -73,25 +92,22 @@ public class UserStoryDomainProvider implements DomainProvider {
|
|||
restOfPagesCallback.callback(new Exception("Error accessing url [" + url + "]", t));
|
||||
}
|
||||
|
||||
private void getUserStoryPage(int pageNumber, Callback<Exception> restOfPagesCallback, Callback<Void> firstPageCallback) {
|
||||
private void getUserStoryPage(int pageNumber, List<UserStory> userStoriesList, String tagsFilter, Callback<Exception> restOfPagesCallback) {
|
||||
Call<UserStories> userStories = mUserStoryDomainProviderService.getUserStories(
|
||||
INCLUDE_ACTIONS_FOR_PLACES,
|
||||
"open",
|
||||
true,
|
||||
mProtocol,
|
||||
TAGS_TO_SEARCH,
|
||||
tagsFilter,
|
||||
pageNumber);
|
||||
Log.d("API-USER-STORY-DOMAINS", "Protocol [" + mProtocol + "] include_actions [" + INCLUDE_ACTIONS_FOR_PLACES + "]");
|
||||
userStories.enqueue(new retrofit2.Callback<UserStories>() {
|
||||
@Override
|
||||
public void onResponse(Call<UserStories> call, Response<UserStories> response) {
|
||||
UserStories data = response.body();
|
||||
allStories.addAll(data.user_stories);
|
||||
userStoriesList.addAll(data.user_stories);
|
||||
if (data.current_page < data.total_pages && data.current_page <= MAX_PAGES_TO_GET) {
|
||||
if (pageNumber == 1 && firstPageCallback != null) {
|
||||
firstPageCallback.callback(null);
|
||||
}
|
||||
getUserStoryPage(pageNumber + 1, restOfPagesCallback, null);
|
||||
getUserStoryPage(pageNumber + 1, userStoriesList, tagsFilter, restOfPagesCallback);
|
||||
return;
|
||||
}
|
||||
restOfPagesCallback.callback(null);
|
||||
|
@ -107,12 +123,16 @@ public class UserStoryDomainProvider implements DomainProvider {
|
|||
private class StoriesFilter {
|
||||
String[] mWords = new String[]{};
|
||||
public StoriesFilter(String filterText) {
|
||||
mWords = filterText.toUpperCase().split("\\s+");
|
||||
mWords = filterText.trim().toUpperCase().split("\\s+");
|
||||
if (mWords.length == 1 && (mWords[0] == null || mWords[0].length() <= 0 ) ) {
|
||||
mWords = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean matches(UserStory story) {
|
||||
if (mWords.length <= 0) {
|
||||
return true;
|
||||
if (mWords == null || mWords.length <= 0) {
|
||||
// No text filter? So filter by tag
|
||||
return story.tagFound;
|
||||
}
|
||||
|
||||
for (String word : mWords) {
|
||||
|
@ -128,6 +148,9 @@ public class UserStoryDomainProvider implements DomainProvider {
|
|||
suggestions.add(story.toDomain());
|
||||
}
|
||||
|
||||
/**
|
||||
* if the story matches this filter criteria it's added into suggestions
|
||||
* */
|
||||
public void filterOrAdd(UserStory story) {
|
||||
if (matches(story)) {
|
||||
addToSuggestions(story);
|
||||
|
@ -144,16 +167,6 @@ public class UserStoryDomainProvider implements DomainProvider {
|
|||
domainCallback.retrieveOk(suggestions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void retrieve(String filterText, DomainCallback domainCallback) {
|
||||
if (!startedToGetFromAPI) {
|
||||
startedToGetFromAPI = true;
|
||||
fillDestinations(filterText, domainCallback);
|
||||
} else {
|
||||
filterChoicesByText(filterText, domainCallback);
|
||||
}
|
||||
}
|
||||
|
||||
public interface UserStoryDomainProviderService {
|
||||
@GET("api/v1/user_stories")
|
||||
Call<UserStories> getUserStories(@Query("include_actions") String includeActions,
|
||||
|
@ -166,12 +179,14 @@ public class UserStoryDomainProvider implements DomainProvider {
|
|||
|
||||
class UserStory {
|
||||
public UserStory() {}
|
||||
String id;
|
||||
String place_name;
|
||||
String path;
|
||||
String thumbnail_url;
|
||||
String place_id;
|
||||
String domain_id;
|
||||
private String searchText;
|
||||
private boolean tagFound; // Locally used
|
||||
|
||||
// New fields? tags, description
|
||||
|
||||
|
|
|
@ -54,27 +54,10 @@ public class DomainAdapter extends RecyclerView.Adapter<DomainAdapter.ViewHolder
|
|||
@Override
|
||||
public void retrieveOk(List<Domain> domain) {
|
||||
if (filterText.length() == 0) {
|
||||
Domain lastVisitedDomain = new Domain(mContext.getString(R.string.your_last_location), mLastLocation, DEFAULT_THUMBNAIL_PLACE);
|
||||
if (!mLastLocation.isEmpty() && mLastLocation.contains("://")) {
|
||||
int startIndex = mLastLocation.indexOf("://");
|
||||
int endIndex = mLastLocation.indexOf("/", startIndex + 3);
|
||||
String toSearch = mLastLocation.substring(0, endIndex + 1).toLowerCase();
|
||||
for (Domain d : domain) {
|
||||
if (d.url.toLowerCase().startsWith(toSearch)) {
|
||||
lastVisitedDomain.thumbnail = d.thumbnail;
|
||||
}
|
||||
}
|
||||
}
|
||||
domain.add(0, lastVisitedDomain);
|
||||
addLastLocation(domain);
|
||||
}
|
||||
|
||||
for (Domain d : domain) {
|
||||
// we override the default picture added in the server by an android specific version
|
||||
if (d.thumbnail != null &&
|
||||
d.thumbnail.endsWith("assets/places/thumbnail-default-place-e5a3f33e773ab699495774990a562f9f7693dc48ef90d8be6985c645a0280f75.png")) {
|
||||
d.thumbnail = DEFAULT_THUMBNAIL_PLACE;
|
||||
}
|
||||
}
|
||||
overrideDefaultThumbnails(domain);
|
||||
|
||||
mDomains = new Domain[domain.size()];
|
||||
mDomains = domain.toArray(mDomains);
|
||||
|
@ -96,6 +79,31 @@ public class DomainAdapter extends RecyclerView.Adapter<DomainAdapter.ViewHolder
|
|||
});
|
||||
}
|
||||
|
||||
private void overrideDefaultThumbnails(List<Domain> domain) {
|
||||
for (Domain d : domain) {
|
||||
// we override the default picture added in the server by an android specific version
|
||||
if (d.thumbnail != null &&
|
||||
d.thumbnail.endsWith("assets/places/thumbnail-default-place-e5a3f33e773ab699495774990a562f9f7693dc48ef90d8be6985c645a0280f75.png")) {
|
||||
d.thumbnail = DEFAULT_THUMBNAIL_PLACE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addLastLocation(List<Domain> domain) {
|
||||
Domain lastVisitedDomain = new Domain(mContext.getString(R.string.your_last_location), mLastLocation, DEFAULT_THUMBNAIL_PLACE);
|
||||
if (!mLastLocation.isEmpty() && mLastLocation.contains("://")) {
|
||||
int startIndex = mLastLocation.indexOf("://");
|
||||
int endIndex = mLastLocation.indexOf("/", startIndex + 3);
|
||||
String toSearch = mLastLocation.substring(0, endIndex + 1).toLowerCase();
|
||||
for (Domain d : domain) {
|
||||
if (d.url.toLowerCase().startsWith(toSearch)) {
|
||||
lastVisitedDomain.thumbnail = d.thumbnail;
|
||||
}
|
||||
}
|
||||
}
|
||||
domain.add(0, lastVisitedDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = mInflater.inflate(R.layout.domain_view, parent, false);
|
||||
|
|
|
@ -66,19 +66,19 @@ ext {
|
|||
def baseFolder = new File(HIFI_ANDROID_PRECOMPILED)
|
||||
def appDir = new File(projectDir, 'app')
|
||||
def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a')
|
||||
def baseUrl = ''
|
||||
def baseUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/android/'
|
||||
|
||||
def qtFile='https://hifi-public.s3.amazonaws.com/austin/android/qt-5.9.3_linux_armv8-libcpp_openssl.tgz'
|
||||
def qtFile='qt-5.9.3_linux_armv8-libcpp_openssl.tgz'
|
||||
def qtChecksum='04599670ccca84bd2b15f6915568eb2d'
|
||||
def qtVersionId='PeoqzN31n.YvLfs9JE2SgHgZ4.IaKAlt'
|
||||
def qtVersionId='8QbCma4ryEPgBYn_8kgYgB10IvNx9I1W'
|
||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||
qtFile = 'https://hifi-public.s3.amazonaws.com/austin/android/qt-5.9.3_osx_armv8-libcpp_openssl.tgz'
|
||||
qtFile = 'qt-5.9.3_osx_armv8-libcpp_openssl.tgz'
|
||||
qtChecksum='4b02de9d67d6bfb202355a808d2d9c59'
|
||||
qtVersionId='HygCmtMLPYioyil0DfXckGVzhw2SXZA9'
|
||||
qtVersionId='2gfgoYCggJGyXxKiazaPGsMs1Gn9j4og'
|
||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
qtFile = 'https://hifi-public.s3.amazonaws.com/austin/android/qt-5.9.3_win_armv8-libcpp_openssl.tgz'
|
||||
qtFile = 'qt-5.9.3_win_armv8-libcpp_openssl.tgz'
|
||||
qtChecksum='c3e25db64002d0f43cf565e0ef708911'
|
||||
qtVersionId='HeVObSVLCBoc7yY7He1oBMvPIH0VkClT'
|
||||
qtVersionId='xKIteC6HO0xrmcWeMmhQcmKyPEsnUrcZ'
|
||||
}
|
||||
|
||||
def packages = [
|
||||
|
@ -88,79 +88,84 @@ def packages = [
|
|||
checksum: qtChecksum,
|
||||
],
|
||||
bullet: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/dependencies/android/bullet-2.88_armv8-libcpp.tgz',
|
||||
file: 'bullet-2.88_armv8-libcpp.tgz',
|
||||
versionId: 'S8YaoED0Cl8sSb8fSV7Q2G1lQJSNDxqg',
|
||||
checksum: '81642779ccb110f8c7338e8739ac38a0',
|
||||
],
|
||||
draco: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/draco_armv8-libcpp.tgz',
|
||||
versionId: 'cA3tVJSmkvb1naA3l6D_Jv2Noh.4yc4m',
|
||||
file: 'draco_armv8-libcpp.tgz',
|
||||
versionId: '3.B.uBj31kWlgND3_R2xwQzT_TP6Dz_8',
|
||||
checksum: '617a80d213a5ec69fbfa21a1f2f738cd',
|
||||
],
|
||||
glad: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/glad_armv8-libcpp.zip',
|
||||
versionId: 'Q9szthzeye8fFyAA.cY26Lgn2B8kezEE',
|
||||
file: 'glad_armv8-libcpp.zip',
|
||||
versionId: 'r5Zran.JSCtvrrB6Q4KaqfIoALPw3lYY',
|
||||
checksum: 'a8ee8584cf1ccd34766c7ddd9d5e5449',
|
||||
],
|
||||
glm: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/dependencies/android/glm-0.9.8.5-patched.tgz',
|
||||
file: 'glm-0.9.8.5-patched.tgz',
|
||||
versionId: 'cskfMoJrFlAeqI3WPxemyO_Cxt7rT9EJ',
|
||||
checksum: '067b5fe16b220b5b1a1039ba51b062ae',
|
||||
],
|
||||
gvr: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/gvrsdk_v1.101.0.tgz',
|
||||
versionId: 'UTberAIFraEfF9IVjoV66u1DTPTopgeY',
|
||||
file: 'gvrsdk_v1.101.0.tgz',
|
||||
versionId: 'nqBV_j81Uc31rC7bKIrlya_Hah4v3y5r',
|
||||
checksum: '57fd02baa069176ba18597a29b6b4fc7',
|
||||
],
|
||||
nvtt: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/nvtt_armv8-libcpp.zip',
|
||||
versionId: 'vLqrqThvpq4gp75BHMAqO6HhfTXaa0An',
|
||||
file: 'nvtt_armv8-libcpp.zip',
|
||||
versionId: 'lmkBVR5t4UF1UUwMwEirnk9H_8Nt90IO',
|
||||
checksum: 'eb46d0b683e66987190ed124aabf8910',
|
||||
sharedLibFolder: 'lib',
|
||||
includeLibs: ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so'],
|
||||
],
|
||||
openssl: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/openssl-1.1.0g_armv8.tgz',
|
||||
versionId: 'DmahmSGFS4ltpHyTdyQvv35WOeUOiib9',
|
||||
file: 'openssl-1.1.0g_armv8.tgz',
|
||||
versionId: 'AiiPjmgUZTgNj7YV1EEx2lL47aDvvvAW',
|
||||
checksum: 'cabb681fbccd79594f65fcc266e02f32',
|
||||
],
|
||||
polyvox: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/polyvox_armv8-libcpp.tgz',
|
||||
versionId: 'LDJtzMTvdm4SAc2KYg8Cg6uwWk4Vq3e3',
|
||||
checksum: '349ad5b72aaf2749ca95d847e60c5314',
|
||||
file: 'polyvox_armv8-libcpp.tgz',
|
||||
versionId: 'A2kbKiNhpIenGq23bKRRzg7IMAI5BI92',
|
||||
checksum: 'dba88b3a098747af4bb169e9eb9af57e',
|
||||
sharedLibFolder: 'lib',
|
||||
includeLibs: ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'],
|
||||
],
|
||||
tbb: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/tbb-2018_U1_armv8_libcpp.tgz',
|
||||
versionId: 'YZliDD8.Menh1IVXKEuLPeO3xAjJ1UdF',
|
||||
file: 'tbb-2018_U1_armv8_libcpp.tgz',
|
||||
versionId: 'mrRbWnv4O4evcM1quRH43RJqimlRtaKB',
|
||||
checksum: '20768f298f53b195e71b414b0ae240c4',
|
||||
sharedLibFolder: 'lib/release',
|
||||
includeLibs: ['libtbb.so', 'libtbbmalloc.so'],
|
||||
],
|
||||
hifiAC: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/libplugins_libhifiCodec.zip',
|
||||
versionId: 'mzKhsRCgVmloqq5bvE.0IwYK1NjGQc_G',
|
||||
file: 'libplugins_libhifiCodec.zip',
|
||||
versionId: 'i31pW.qNbvFOXRxbyiJUxg3sphaFNmZU',
|
||||
checksum: '9412a8e12c88a4096c1fc843bb9fe52d',
|
||||
sharedLibFolder: '',
|
||||
includeLibs: ['libplugins_libhifiCodec.so']
|
||||
],
|
||||
etc2comp: [
|
||||
file: 'etc2comp-patched-armv8-libcpp.tgz',
|
||||
versionId: 'bHhGECRAQR1vkpshBcK6ByNc1BQIM8gU',
|
||||
checksum: '14b02795d774457a33bbc60e00a786bc'
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
def scribeLocalFile='scribe' + EXEC_SUFFIX
|
||||
|
||||
def scribeFile='https://hifi-public.s3.amazonaws.com/austin/android/scribe_linux_x86_64'
|
||||
def scribeFile='scribe_linux_x86_64'
|
||||
def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6'
|
||||
def scribeVersion='wgpf4dB2Ltzg4Lb2jJ4nPFsHoDkmK_OO'
|
||||
def scribeVersion='u_iTrJDaE95i2abTPXOpPZckGBIim53G'
|
||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||
scribeFile = 'https://hifi-public.s3.amazonaws.com/austin/android/scribe_osx_x86_64'
|
||||
scribeFile = 'scribe_osx_x86_64'
|
||||
scribeChecksum='72db9d32d4e1e50add755570ac5eb749'
|
||||
scribeVersion='o_NbPrktzEYtBkQf3Tn7zc1nZWzM52w6'
|
||||
scribeVersion='DAW0DmnjCRib4MD8x93bgc2Z2MpPojZC'
|
||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
scribeFile = 'https://hifi-public.s3.amazonaws.com/austin/android/scribe_win32_x86_64.exe'
|
||||
scribeFile = 'scribe_win32_x86_64.exe'
|
||||
scribeChecksum='678e43d290c90fda670c6fefe038a06d'
|
||||
scribeVersion='GCCJxlmd2irvNOFWfZR0U1UCLHndHQrC'
|
||||
scribeVersion='PuullrA_bPlO9kXZRt8rLe536X1UI.m7'
|
||||
}
|
||||
|
||||
def options = [
|
||||
|
@ -361,6 +366,7 @@ task verifyOpenSSL(type: Verify) { def p = packages['openssl']; src new File(bas
|
|||
task verifyPolyvox(type: Verify) { def p = packages['polyvox']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyTBB(type: Verify) { def p = packages['tbb']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyHifiAC(type: Verify) { def p = packages['hifiAC']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyEtc2Comp(type: Verify) { def p = packages['etc2comp']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
|
||||
task verifyDependencyDownloads(dependsOn: downloadDependencies) { }
|
||||
verifyDependencyDownloads.dependsOn verifyQt
|
||||
|
@ -371,6 +377,7 @@ verifyDependencyDownloads.dependsOn verifyOpenSSL
|
|||
verifyDependencyDownloads.dependsOn verifyPolyvox
|
||||
verifyDependencyDownloads.dependsOn verifyTBB
|
||||
verifyDependencyDownloads.dependsOn verifyHifiAC
|
||||
verifyDependencyDownloads.dependsOn verifyEtc2Comp
|
||||
|
||||
task extractDependencies(dependsOn: verifyDependencyDownloads) {
|
||||
doLast {
|
||||
|
@ -608,4 +615,4 @@ task testElf (dependsOn: 'externalNativeBuildDebug') {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
*/
|
|
@ -233,7 +233,6 @@ OctreeServer::OctreeServer(ReceivedMessage& message) :
|
|||
_argc(0),
|
||||
_argv(NULL),
|
||||
_parsedArgV(NULL),
|
||||
_httpManager(NULL),
|
||||
_statusPort(0),
|
||||
_packetsPerClientPerInterval(10),
|
||||
_packetsTotalPerInterval(DEFAULT_PACKETS_PER_INTERVAL),
|
||||
|
@ -285,7 +284,7 @@ void OctreeServer::initHTTPManager(int port) {
|
|||
QString documentRoot = QString("%1/web").arg(PathUtils::getAppDataPath());
|
||||
|
||||
// setup an httpManager with us as the request handler and the parent
|
||||
_httpManager = new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this, this);
|
||||
_httpManager.reset(new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this));
|
||||
}
|
||||
|
||||
bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||
|
|
|
@ -183,7 +183,7 @@ protected:
|
|||
|
||||
bool _isShuttingDown = false;
|
||||
|
||||
HTTPManager* _httpManager;
|
||||
std::unique_ptr<HTTPManager> _httpManager;
|
||||
int _statusPort;
|
||||
QString _statusHost;
|
||||
|
||||
|
|
4
cmake/externals/LibOVR/CMakeLists.txt
vendored
4
cmake/externals/LibOVR/CMakeLists.txt
vendored
|
@ -17,8 +17,8 @@ if (WIN32)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://static.oculus.com/sdk-downloads/1.11.0/Public/1486063832/ovr_sdk_win_1.11.0_public.zip
|
||||
URL_MD5 ea484403757cbfdfa743b6577fb1f9d2
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.26.0_public.zip
|
||||
URL_MD5 06804ff9727b910dcd04a37c800053b5
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
PATCH_COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/LibOVRCMakeLists.txt" <SOURCE_DIR>/CMakeLists.txt
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
2
cmake/externals/LibOVR/LibOVRCMakeLists.txt
vendored
2
cmake/externals/LibOVR/LibOVRCMakeLists.txt
vendored
|
@ -4,7 +4,7 @@ project(LibOVR)
|
|||
include_directories(LibOVR/Include LibOVR/Src)
|
||||
file(GLOB HEADER_FILES LibOVR/Include/*.h)
|
||||
file(GLOB EXTRA_HEADER_FILES LibOVR/Include/Extras/*.h)
|
||||
file(GLOB_RECURSE SOURCE_FILES LibOVR/Src/*.c LibOVR/Src/*.cpp)
|
||||
file(GLOB_RECURSE SOURCE_FILES LibOVR/Shim/*.c LibOVR/Shim/*.cpp)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DOVR_BUILD_DEBUG")
|
||||
add_library(LibOVR STATIC ${SOURCE_FILES} ${HEADER_FILES} ${EXTRA_HEADER_FILES})
|
||||
set_target_properties(LibOVR PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
|
55
cmake/externals/etc2comp/CMakeLists.txt
vendored
Normal file
55
cmake/externals/etc2comp/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
set(EXTERNAL_NAME etc2comp)
|
||||
|
||||
if (ANDROID)
|
||||
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
set(EXTRA_CMAKE_FLAGS -DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++)
|
||||
endif ()
|
||||
|
||||
include(ExternalProject)
|
||||
# We use a patched version of etc2comp that properly generates all the necessary mips
|
||||
# See https://github.com/google/etc2comp/pull/29
|
||||
# We also use part of https://github.com/google/etc2comp/pull/1, which fixes a bug
|
||||
# that would override CMAKE_CXX_FLAGS
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/etc2comp-patched.zip
|
||||
URL_MD5 4c96153eb179acbe619e3d99d3330595
|
||||
CMAKE_ARGS ${ANDROID_CMAKE_ARGS} ${EXTRA_CMAKE_FLAGS}
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/build/EtcLib/Debug/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp debug library")
|
||||
|
||||
# use generator expression to ensure the correct library is found when building different configurations in VS
|
||||
set(_LIB_FOLDER "$<$<CONFIG:RelWithDebInfo>:build/EtcLib/RelWithDebInfo>")
|
||||
set(_LIB_FOLDER "${_LIB_FOLDER}$<$<CONFIG:MinSizeRel>:build/EtcLib/MinSizeRel>")
|
||||
set(_LIB_FOLDER "${_LIB_FOLDER}$<$<OR:$<CONFIG:Release>,$<CONFIG:Debug>>:build/EtcLib/Release>")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/${_LIB_FOLDER}/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp release library")
|
||||
elseif (APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/build/EtcLib/Debug/libEtcLib.a CACHE FILEPATH "Path to EtcLib debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/build/EtcLib/Release/libEtcLib.a CACHE FILEPATH "Path to EtcLib release library")
|
||||
else ()
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Path to EtcLib debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/build/EtcLib/libEtcLib.a CACHE FILEPATH "Path to EtcLib release library")
|
||||
endif ()
|
||||
|
||||
set(ETC_INCLUDE_DIR ${SOURCE_DIR}/EtcLib/Etc CACHE FILEPATH "Path to Etc2Comp/Etc include directory")
|
||||
set(ETCCODEC_INCLUDE_DIR ${SOURCE_DIR}/EtcLib/EtcCodec CACHE FILEPATH "Path to Etc2Comp/EtcCodec include directory")
|
||||
# ETC2COMP_INCLUDE_DIRS will be set later by FindEtc2Comp
|
22
cmake/macros/TargetEtc2Comp.cmake
Normal file
22
cmake/macros/TargetEtc2Comp.cmake
Normal file
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# Copyright 2018 High Fidelity, Inc.
|
||||
# Created by Sam Gondelman on 5/2/2018
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_ETC2COMP)
|
||||
if (ANDROID)
|
||||
set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/etc2comp)
|
||||
set(ETC2COMP_INCLUDE_DIRS "${INSTALL_DIR}/include/Etc" "${INSTALL_DIR}/include/EtcCodec")
|
||||
set(ETC2COMP_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libEtcLib.a)
|
||||
set(ETC2COMP_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libEtcLib.a)
|
||||
select_library_configurations(ETC2COMP)
|
||||
else()
|
||||
add_dependency_external_projects(etc2comp)
|
||||
find_package(Etc2Comp REQUIRED)
|
||||
endif()
|
||||
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${ETC2COMP_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${ETC2COMP_LIBRARIES})
|
||||
endmacro()
|
37
cmake/modules/FindEtc2Comp.cmake
Normal file
37
cmake/modules/FindEtc2Comp.cmake
Normal file
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
# FindEtc2Comp.cmake
|
||||
#
|
||||
# Try to find the Etc2Comp compression library.
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# ETC2COMP_FOUND - system found Etc2Comp
|
||||
# ETC2COMP_INCLUDE_DIRS - the Etc2Comp include directory
|
||||
# ETC2COMP_LIBRARIES - link to this to use Etc2Comp
|
||||
#
|
||||
# Created on 5/2/2018 by Sam Gondelman
|
||||
# Copyright 2018 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
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("etc2comp")
|
||||
|
||||
find_path(ETC_INCLUDE_DIR NAMES Etc.h HINTS ${ETC2COMP_SEARCH_DIRS})
|
||||
find_path(ETCCODEC_INCLUDE_DIR NAMES EtcBlock4x4.h HINTS ${ETC2COMP_SEARCH_DIRS})
|
||||
set(ETC2COMP_INCLUDE_DIRS "${ETC_INCLUDE_DIR}" "${ETCCODEC_INCLUDE_DIR}")
|
||||
|
||||
find_library(ETC2COMP_LIBRARY_DEBUG NAMES ETC2COMP ETC2COMP_LIB PATH_SUFFIXES EtcLib/Debug HINTS ${ETC2COMP_SEARCH_DIRS})
|
||||
find_library(ETC2COMP_LIBRARY_RELEASE NAMES ETC2COMP ETC2COMP_LIB PATH_SUFFIXES EtcLib/Release EtcLib HINTS ${ETC2COMP_SEARCH_DIRS})
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(ETC2COMP)
|
||||
|
||||
set(ETC2COMP_LIBRARIES ${ETC2COMP_LIBRARY})
|
||||
|
||||
find_package_handle_standard_args(ETC2COMP "Could NOT find ETC2COMP, try to set the path to ETC2COMP root folder in the system variable ETC2COMP_ROOT_DIR or create a directory etc2comp in HIFI_LIB_DIR and paste the necessary files there"
|
||||
ETC2COMP_INCLUDE_DIRS ETC2COMP_LIBRARIES)
|
||||
|
||||
mark_as_advanced(ETC2COMP_INCLUDE_DIRS ETC2COMP_LIBRARIES ETC2COMP_SEARCH_DIRS)
|
|
@ -16,6 +16,8 @@
|
|||
#include <openssl/x509.h>
|
||||
#include <random>
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <Assignment.h>
|
||||
|
||||
|
|
|
@ -149,7 +149,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
QCoreApplication(argc, argv),
|
||||
_gatekeeper(this),
|
||||
_httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
|
||||
_httpsManager(NULL),
|
||||
_allAssignments(),
|
||||
_unfulfilledAssignments(),
|
||||
_isUsingDTLS(false),
|
||||
|
@ -385,6 +384,8 @@ DomainServer::~DomainServer() {
|
|||
_contentManager->terminate();
|
||||
}
|
||||
|
||||
DependencyManager::destroy<AccountManager>();
|
||||
|
||||
// cleanup the AssetClient thread
|
||||
DependencyManager::destroy<AssetClient>();
|
||||
_assetClientThread.quit();
|
||||
|
@ -439,7 +440,7 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
|||
QSslCertificate sslCertificate(&certFile);
|
||||
QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8());
|
||||
|
||||
_httpsManager = new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this, this);
|
||||
_httpsManager.reset(new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this));
|
||||
|
||||
qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT;
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ private:
|
|||
DomainGatekeeper _gatekeeper;
|
||||
|
||||
HTTPManager _httpManager;
|
||||
HTTPSManager* _httpsManager;
|
||||
std::unique_ptr<HTTPSManager> _httpsManager;
|
||||
|
||||
QHash<QUuid, SharedAssignmentPointer> _allAssignments;
|
||||
QQueue<SharedAssignmentPointer> _unfulfilledAssignments;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <QtCore/QDataStream>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
|
|
@ -133,13 +133,7 @@ if (APPLE)
|
|||
# set where in the bundle to put the resources file
|
||||
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
set(DISCOVERED_RESOURCES "")
|
||||
|
||||
# use the add_resources_to_os_x_bundle macro to recurse into resources
|
||||
add_resources_to_os_x_bundle("${CMAKE_CURRENT_SOURCE_DIR}/resources")
|
||||
|
||||
# append the discovered resources to our list of interface sources
|
||||
list(APPEND INTERFACE_SRCS ${DISCOVERED_RESOURCES})
|
||||
list(APPEND INTERFACE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME})
|
||||
endif()
|
||||
|
||||
|
@ -316,18 +310,27 @@ if (APPLE)
|
|||
set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources")
|
||||
set(RESOURCES_DEV_DIR "$<TARGET_FILE_DIR:${TARGET_NAME}>/../Resources")
|
||||
|
||||
# copy script files beside the executable
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
# copy script files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/scripts"
|
||||
"${RESOURCES_DEV_DIR}/scripts"
|
||||
)
|
||||
|
||||
# copy JSDoc files beside the executable
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
"${CMAKE_SOURCE_DIR}/scripts"
|
||||
"${RESOURCES_DEV_DIR}/scripts"
|
||||
# copy JSDoc files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
"${RESOURCES_DEV_DIR}/jsdoc"
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
"${RESOURCES_DEV_DIR}/jsdoc"
|
||||
# copy the resources files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${RESOURCES_RCC}"
|
||||
"${RESOURCES_DEV_DIR}"
|
||||
# FIXME, the edit script code loads HTML from the scripts folder
|
||||
# which in turn relies on CSS that refers to the fonts. In theory
|
||||
# we should be able to modify the CSS to reference the QRC path to
|
||||
# the ttf files, but doing so generates a CORS policy violation,
|
||||
# so we have to retain a copy of the fonts outside of the resources binary
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/resources/fonts"
|
||||
"${RESOURCES_DEV_DIR}/fonts"
|
||||
)
|
||||
|
||||
# call the fixup_interface macro to add required bundling commands for installation
|
||||
|
@ -356,13 +359,10 @@ else()
|
|||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/tutorial.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/tutorial.json"
|
||||
)
|
||||
|
||||
# copy JSDoc files beside the executable
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
# copy JSDoc files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
"${INTERFACE_EXEC_DIR}/jsdoc"
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
"${INTERFACE_EXEC_DIR}/jsdoc"
|
||||
)
|
||||
|
||||
# link target to external libraries
|
||||
|
|
|
@ -2,88 +2,88 @@ name = mannequin
|
|||
type = body+head
|
||||
scale = 1
|
||||
filename = mannequin/mannequin.baked.fbx
|
||||
joint = jointRoot = Hips
|
||||
joint = jointNeck = Neck
|
||||
joint = jointLean = Spine
|
||||
joint = jointLeftHand = LeftHand
|
||||
joint = jointHead = Head
|
||||
joint = jointEyeLeft = LeftEye
|
||||
joint = jointEyeRight = RightEye
|
||||
joint = jointRoot = Hips
|
||||
joint = jointLeftHand = LeftHand
|
||||
joint = jointRightHand = RightHand
|
||||
joint = jointNeck = Neck
|
||||
joint = jointHead = Head
|
||||
freeJoint = LeftArm
|
||||
freeJoint = LeftForeArm
|
||||
freeJoint = RightArm
|
||||
freeJoint = RightForeArm
|
||||
bs = EyeBlink_L = blink = 1
|
||||
bs = JawOpen = mouth_Open = 1
|
||||
bs = LipsFunnel = Oo = 1
|
||||
bs = BrowsU_L = brow_Up = 1
|
||||
jointIndex = RightHandPinky2 = 19
|
||||
jointIndex = LeftHandMiddle4 = 61
|
||||
jointIndex = LeftHand = 41
|
||||
jointIndex = LeftHandRing4 = 49
|
||||
jointIndex = RightHandMiddle3 = 36
|
||||
jointIndex = LeftHandThumb4 = 57
|
||||
jointIndex = RightToe_End = 10
|
||||
jointIndex = LeftHandRing1 = 46
|
||||
jointIndex = LeftForeArm = 40
|
||||
jointIndex = RightHandIndex4 = 29
|
||||
jointIndex = LeftShoulder = 38
|
||||
jointIndex = RightHandMiddle4 = 37
|
||||
jointIndex = RightShoulder = 14
|
||||
jointIndex = LeftLeg = 2
|
||||
jointIndex = LeftToe_End = 5
|
||||
jointIndex = Hips = 0
|
||||
jointIndex = RightFoot = 8
|
||||
jointIndex = RightHandThumb2 = 31
|
||||
jointIndex = LeftHandMiddle3 = 60
|
||||
jointIndex = RightHandThumb1 = 30
|
||||
jointIndex = Neck = 62
|
||||
jointIndex = Spine = 11
|
||||
jointIndex = RightHandThumb4 = 33
|
||||
jointIndex = RightHandMiddle1 = 34
|
||||
jointIndex = LeftHandIndex4 = 53
|
||||
jointIndex = face = 68
|
||||
jointIndex = RightHandRing3 = 24
|
||||
jointIndex = LeftHandPinky4 = 45
|
||||
jointIndex = LeftHandMiddle2 = 59
|
||||
jointIndex = RightHandThumb3 = 32
|
||||
bs = EyeBlink_L = blink = 1
|
||||
jointIndex = LeftHandPinky3 = 44
|
||||
jointIndex = HeadTop_End = 66
|
||||
jointIndex = Spine1 = 12
|
||||
jointIndex = LeftHandRing3 = 48
|
||||
jointIndex = mannequin1 = 67
|
||||
jointIndex = RightEye = 65
|
||||
jointIndex = RightHandRing4 = 25
|
||||
jointIndex = RightHandPinky4 = 21
|
||||
jointIndex = LeftHandRing2 = 47
|
||||
jointIndex = RightHandIndex3 = 28
|
||||
jointIndex = RightUpLeg = 6
|
||||
jointIndex = LeftArm = 39
|
||||
jointIndex = LeftHandThumb3 = 56
|
||||
jointIndex = RightHandIndex2 = 27
|
||||
jointIndex = RightForeArm = 16
|
||||
jointIndex = RightArm = 15
|
||||
jointIndex = RightHandRing2 = 23
|
||||
jointIndex = LeftHandMiddle1 = 58
|
||||
jointIndex = Spine2 = 13
|
||||
jointIndex = LeftHandThumb2 = 55
|
||||
jointIndex = RightHandMiddle2 = 35
|
||||
jointIndex = RightHandPinky1 = 18
|
||||
jointIndex = LeftUpLeg = 1
|
||||
jointIndex = RightLeg = 7
|
||||
jointIndex = LeftHandIndex2 = 51
|
||||
jointIndex = LeftHand = 41
|
||||
jointIndex = RightHandMiddle1 = 34
|
||||
jointIndex = LeftHandPinky4 = 45
|
||||
jointIndex = RightHand = 17
|
||||
jointIndex = LeftHandIndex3 = 52
|
||||
jointIndex = LeftFoot = 3
|
||||
jointIndex = RightHandPinky3 = 20
|
||||
jointIndex = RightHandIndex1 = 26
|
||||
jointIndex = LeftHandPinky1 = 42
|
||||
jointIndex = RightToeBase = 9
|
||||
jointIndex = LeftHandIndex1 = 50
|
||||
jointIndex = LeftToeBase = 4
|
||||
jointIndex = LeftHandPinky2 = 43
|
||||
jointIndex = RightHandRing1 = 22
|
||||
jointIndex = LeftHandThumb1 = 54
|
||||
jointIndex = LeftEye = 64
|
||||
jointIndex = LeftFoot = 3
|
||||
jointIndex = Head = 63
|
||||
jointIndex = Spine1 = 12
|
||||
jointIndex = RightHandRing4 = 25
|
||||
jointIndex = RightHandPinky1 = 18
|
||||
jointIndex = LeftHandIndex1 = 50
|
||||
jointIndex = RightHandIndex3 = 28
|
||||
jointIndex = LeftHandIndex3 = 52
|
||||
jointIndex = LeftToe_End = 5
|
||||
jointIndex = RightArm = 15
|
||||
jointIndex = RightHandRing3 = 24
|
||||
jointIndex = RightHandThumb2 = 31
|
||||
jointIndex = Spine2 = 13
|
||||
jointIndex = HeadTop_End = 66
|
||||
jointIndex = LeftToeBase = 4
|
||||
jointIndex = RightUpLeg = 6
|
||||
jointIndex = RightForeArm = 16
|
||||
jointIndex = LeftHandMiddle1 = 58
|
||||
jointIndex = LeftHandRing3 = 48
|
||||
jointIndex = RightHandPinky4 = 21
|
||||
jointIndex = RightHandIndex1 = 26
|
||||
jointIndex = Hips = 0
|
||||
jointIndex = RightEye = 65
|
||||
jointIndex = RightHandPinky2 = 19
|
||||
jointIndex = LeftHandMiddle2 = 59
|
||||
jointIndex = LeftHandPinky1 = 42
|
||||
jointIndex = LeftHandRing4 = 49
|
||||
jointIndex = RightFoot = 8
|
||||
jointIndex = RightHandIndex2 = 27
|
||||
jointIndex = RightToe_End = 10
|
||||
jointIndex = RightHandThumb3 = 32
|
||||
jointIndex = LeftHandMiddle3 = 60
|
||||
jointIndex = LeftHandThumb4 = 57
|
||||
jointIndex = LeftHandMiddle4 = 61
|
||||
jointIndex = LeftHandThumb1 = 54
|
||||
jointIndex = LeftHandThumb3 = 56
|
||||
jointIndex = body = 67
|
||||
jointIndex = LeftArm = 39
|
||||
jointIndex = RightToeBase = 9
|
||||
jointIndex = LeftEye = 64
|
||||
jointIndex = RightLeg = 7
|
||||
jointIndex = face = 68
|
||||
jointIndex = LeftForeArm = 40
|
||||
jointIndex = RightHandThumb4 = 33
|
||||
jointIndex = RightHandRing1 = 22
|
||||
jointIndex = LeftUpLeg = 1
|
||||
jointIndex = LeftHandPinky2 = 43
|
||||
jointIndex = LeftLeg = 2
|
||||
jointIndex = LeftHandIndex4 = 53
|
||||
jointIndex = RightHandThumb1 = 30
|
||||
jointIndex = LeftHandRing2 = 47
|
||||
jointIndex = RightHandMiddle2 = 35
|
||||
jointIndex = RightHandMiddle3 = 36
|
||||
jointIndex = Spine = 11
|
||||
jointIndex = RightHandMiddle4 = 37
|
||||
jointIndex = LeftHandIndex2 = 51
|
||||
jointIndex = RightHandRing2 = 23
|
||||
jointIndex = LeftHandThumb2 = 55
|
||||
jointIndex = LeftShoulder = 38
|
||||
jointIndex = Neck = 62
|
||||
jointIndex = RightHandIndex4 = 29
|
||||
jointIndex = LeftHandRing1 = 46
|
||||
jointIndex = RightShoulder = 14
|
||||
|
|
BIN
interface/resources/meshes/mannequin/Eyes.png
Normal file
BIN
interface/resources/meshes/mannequin/Eyes.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 1,002 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
interface/resources/meshes/mannequin/lambert1_Roughness.png
Normal file
BIN
interface/resources/meshes/mannequin/lambert1_Roughness.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 525 KiB |
Binary file not shown.
Binary file not shown.
|
@ -331,6 +331,7 @@ ModalWindow {
|
|||
}
|
||||
|
||||
onFolderChanged: {
|
||||
d.clearSelection();
|
||||
fileTableModel.update(); // Update once the data from the folder change is available.
|
||||
}
|
||||
|
||||
|
@ -450,7 +451,7 @@ ModalWindow {
|
|||
rows = 0,
|
||||
i;
|
||||
|
||||
var newFilesModel = filesModelBuilder.createObject(root);
|
||||
filesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
|
@ -472,7 +473,7 @@ ModalWindow {
|
|||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, newFilesModel.get(middle)[sortField])) {
|
||||
if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
|
@ -481,7 +482,7 @@ ModalWindow {
|
|||
}
|
||||
}
|
||||
|
||||
newFilesModel.insert(lower, {
|
||||
filesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
|
@ -492,9 +493,6 @@ ModalWindow {
|
|||
|
||||
rows++;
|
||||
}
|
||||
filesModel = newFilesModel;
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -332,6 +332,7 @@ ModalWindow {
|
|||
}
|
||||
|
||||
onFolderChanged: {
|
||||
d.clearSelection();
|
||||
fileTableModel.update(); // Update once the data from the folder change is available.
|
||||
}
|
||||
|
||||
|
@ -451,7 +452,7 @@ ModalWindow {
|
|||
rows = 0,
|
||||
i;
|
||||
|
||||
var newFilesModel = filesModelBuilder.createObject(root);
|
||||
filesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
|
@ -473,7 +474,7 @@ ModalWindow {
|
|||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, newFilesModel.get(middle)[sortField])) {
|
||||
if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
|
@ -482,7 +483,7 @@ ModalWindow {
|
|||
}
|
||||
}
|
||||
|
||||
newFilesModel.insert(lower, {
|
||||
filesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
|
@ -493,9 +494,6 @@ ModalWindow {
|
|||
|
||||
rows++;
|
||||
}
|
||||
filesModel = newFilesModel;
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -295,7 +295,8 @@ TabletModalWindow {
|
|||
}
|
||||
|
||||
onFolderChanged: {
|
||||
fileTableModel.update()
|
||||
d.clearSelection();
|
||||
fileTableModel.update();
|
||||
}
|
||||
|
||||
function getItem(index, field) {
|
||||
|
@ -413,7 +414,7 @@ TabletModalWindow {
|
|||
rows = 0,
|
||||
i;
|
||||
|
||||
var newFilesModel = filesModelBuilder.createObject(root);
|
||||
filesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
|
@ -435,7 +436,7 @@ TabletModalWindow {
|
|||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, newFilesModel.get(middle)[sortField])) {
|
||||
if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
|
@ -444,7 +445,7 @@ TabletModalWindow {
|
|||
}
|
||||
}
|
||||
|
||||
newFilesModel.insert(lower, {
|
||||
filesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
|
@ -455,9 +456,6 @@ TabletModalWindow {
|
|||
|
||||
rows++;
|
||||
}
|
||||
filesModel = newFilesModel;
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -319,10 +319,10 @@ Item {
|
|||
visible: thisNameCard.userName !== "";
|
||||
// Size
|
||||
width: parent.width
|
||||
height: usernameTextPixelSize + 4
|
||||
height: paintedHeight
|
||||
// Anchors
|
||||
anchors.top: isMyCard ? myDisplayName.bottom : pal.activeTab == "nearbyTab" ? displayNameContainer.bottom : undefined //(parent.height - displayNameTextPixelSize/2));
|
||||
anchors.verticalCenter: pal.activeTab == "connectionsTab" && !isMyCard ? avatarImage.verticalCenter : undefined
|
||||
anchors.top: isMyCard ? myDisplayName.bottom : pal.activeTab == "nearbyTab" ? displayNameContainer.bottom : avatarImage.top //(parent.height - displayNameTextPixelSize/2));
|
||||
anchors.bottom: pal.activeTab === "connectionsTab" && !isMyCard ? avatarImage.bottom : undefined
|
||||
anchors.left: avatarImage.right;
|
||||
anchors.leftMargin: avatarImage.visible ? 5 : 0;
|
||||
anchors.rightMargin: 5;
|
||||
|
|
|
@ -163,7 +163,6 @@ Item {
|
|||
|
||||
Rectangle {
|
||||
id: contextCard;
|
||||
z: 2;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 30;
|
||||
anchors.top: parent.top;
|
||||
|
@ -337,7 +336,6 @@ Item {
|
|||
|
||||
Rectangle {
|
||||
id: permissionExplanationCard;
|
||||
z: 1;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 30;
|
||||
anchors.top: parent.top;
|
||||
|
@ -596,8 +594,8 @@ Item {
|
|||
anchors.fill: parent;
|
||||
hoverEnabled: enabled;
|
||||
onClicked: {
|
||||
contextCard.z = 1;
|
||||
permissionExplanationCard.z = 0;
|
||||
contextCard.visible = true;
|
||||
permissionExplanationCard.visible = false;
|
||||
root.sendToPurchases({ method: 'flipCard' });
|
||||
}
|
||||
onEntered: {
|
||||
|
@ -779,8 +777,8 @@ Item {
|
|||
noPermissionGlyph.color = hifi.colors.redAccent;
|
||||
}
|
||||
onClicked: {
|
||||
contextCard.z = 0;
|
||||
permissionExplanationCard.z = 1;
|
||||
contextCard.visible = false;
|
||||
permissionExplanationCard.visible = true;
|
||||
root.sendToPurchases({ method: 'flipCard' });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick 2.7
|
||||
import Qt.labs.folderlistmodel 2.1
|
||||
import Qt.labs.settings 1.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
import QtQuick.Controls 1.4 as QQC1
|
||||
import QtQuick.Controls 2.3
|
||||
|
||||
import ".."
|
||||
import "../../../controls-uit"
|
||||
|
@ -30,6 +30,8 @@ Rectangle {
|
|||
|
||||
color: hifi.colors.baseGray;
|
||||
|
||||
property var filesModel: ListModel { }
|
||||
|
||||
Settings {
|
||||
category: "FileDialog"
|
||||
property alias width: root.width
|
||||
|
@ -149,7 +151,7 @@ Rectangle {
|
|||
|
||||
ComboBox {
|
||||
id: pathSelector
|
||||
anchors {
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: hifi.dimensions.contentMargin.y
|
||||
left: navControls.right
|
||||
|
@ -247,7 +249,9 @@ Rectangle {
|
|||
}
|
||||
|
||||
currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath);
|
||||
currentSelectionIsFolder = fileTableView.model.isFolder(row);
|
||||
currentSelectionIsFolder = fileTableView.model !== filesModel ?
|
||||
fileTableView.model.isFolder(row) :
|
||||
fileTableModel.isFolder(row);
|
||||
if (root.selectDirectory || !currentSelectionIsFolder) {
|
||||
currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl));
|
||||
} else {
|
||||
|
@ -287,6 +291,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onFolderChanged: {
|
||||
d.clearSelection();
|
||||
fileTableModel.update(); // Update once the data from the folder change is available.
|
||||
}
|
||||
|
||||
|
@ -327,7 +332,12 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
Component {
|
||||
id: filesModelBuilder
|
||||
ListModel { }
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: fileTableModel
|
||||
|
||||
// FolderListModel has a couple of problems:
|
||||
|
@ -379,7 +389,11 @@ Rectangle {
|
|||
if (row === -1) {
|
||||
return false;
|
||||
}
|
||||
return get(row).fileIsDir;
|
||||
return filesModel.get(row).fileIsDir;
|
||||
}
|
||||
|
||||
function get(row) {
|
||||
return filesModel.get(row)
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
@ -397,7 +411,7 @@ Rectangle {
|
|||
rows = 0,
|
||||
i;
|
||||
|
||||
clear();
|
||||
filesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
|
@ -419,7 +433,7 @@ Rectangle {
|
|||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, get(middle)[sortField])) {
|
||||
if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
|
@ -428,7 +442,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
insert(lower, {
|
||||
filesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
|
@ -439,8 +453,6 @@ Rectangle {
|
|||
|
||||
rows++;
|
||||
}
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -465,12 +477,12 @@ Rectangle {
|
|||
sortIndicatorOrder: Qt.AscendingOrder
|
||||
sortIndicatorVisible: true
|
||||
|
||||
model: fileTableModel
|
||||
model: filesModel
|
||||
|
||||
function updateSort() {
|
||||
model.sortOrder = sortIndicatorOrder;
|
||||
model.sortColumn = sortIndicatorColumn;
|
||||
model.update();
|
||||
fileTableModel.sortOrder = sortIndicatorOrder;
|
||||
fileTableModel.sortColumn = sortIndicatorColumn;
|
||||
fileTableModel.update();
|
||||
}
|
||||
|
||||
onSortIndicatorColumnChanged: { updateSort(); }
|
||||
|
@ -522,7 +534,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
TableViewColumn {
|
||||
QQC1.TableViewColumn {
|
||||
id: fileNameColumn
|
||||
role: "fileName"
|
||||
title: "Name"
|
||||
|
@ -530,7 +542,7 @@ Rectangle {
|
|||
movable: false
|
||||
resizable: true
|
||||
}
|
||||
TableViewColumn {
|
||||
QQC1.TableViewColumn {
|
||||
id: fileMofifiedColumn
|
||||
role: "fileModified"
|
||||
title: "Date"
|
||||
|
@ -539,7 +551,7 @@ Rectangle {
|
|||
resizable: true
|
||||
visible: !selectDirectory
|
||||
}
|
||||
TableViewColumn {
|
||||
QQC1.TableViewColumn {
|
||||
role: "fileSize"
|
||||
title: "Size"
|
||||
width: fileTableView.width - fileNameColumn.width - fileMofifiedColumn.width
|
||||
|
@ -554,11 +566,12 @@ Rectangle {
|
|||
}
|
||||
|
||||
function navigateToCurrentRow() {
|
||||
var currentModel = fileTableView.model !== filesModel ? fileTableView.model : fileTableModel
|
||||
var row = fileTableView.currentRow
|
||||
var isFolder = model.isFolder(row);
|
||||
var file = model.get(row).filePath;
|
||||
var isFolder = currentModel.isFolder(row);
|
||||
var file = currentModel.get(row).filePath;
|
||||
if (isFolder) {
|
||||
fileTableView.model.folder = helper.pathToUrl(file);
|
||||
currentModel.folder = helper.pathToUrl(file);
|
||||
} else {
|
||||
okAction.trigger();
|
||||
}
|
||||
|
@ -573,7 +586,8 @@ Rectangle {
|
|||
var newPrefix = prefix + event.text.toLowerCase();
|
||||
var matchedIndex = -1;
|
||||
for (var i = 0; i < model.count; ++i) {
|
||||
var name = model.get(i).fileName.toLowerCase();
|
||||
var name = model !== filesModel ? model.get(i).fileName.toLowerCase() :
|
||||
filesModel.get(i).fileName.toLowerCase();
|
||||
if (0 === name.indexOf(newPrefix)) {
|
||||
matchedIndex = i;
|
||||
break;
|
||||
|
|
|
@ -15,6 +15,17 @@
|
|||
|
||||
#include <QObject>
|
||||
|
||||
/**jsdoc
|
||||
* @namespace HifiAbout
|
||||
*
|
||||
* @hifi-interface
|
||||
* @hifi-client-entity
|
||||
*
|
||||
* @property {string} buildDate
|
||||
* @property {string} buildVersion
|
||||
* @property {string} qtVersion
|
||||
*/
|
||||
|
||||
class AboutUtil : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -30,6 +41,11 @@ public:
|
|||
QString getQtVersion() const;
|
||||
|
||||
public slots:
|
||||
|
||||
/**jsdoc
|
||||
* @function HifiAbout.openUrl
|
||||
* @param {string} url
|
||||
*/
|
||||
void openUrl(const QString &url) const;
|
||||
private:
|
||||
AboutUtil(QObject* parent = nullptr);
|
||||
|
|
|
@ -334,7 +334,11 @@ static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" };
|
|||
static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
|
||||
#endif
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;
|
||||
#else
|
||||
static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4;
|
||||
#endif
|
||||
|
||||
// For processing on QThreadPool, we target a number of threads after reserving some
|
||||
// based on how many are being consumed by the application and the display plugin. However,
|
||||
|
@ -798,15 +802,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir);
|
||||
}
|
||||
|
||||
// FIXME fix the OSX installer to install the resources.rcc binary instead of resource files and remove
|
||||
// this conditional exclusion
|
||||
#if !defined(Q_OS_OSX)
|
||||
{
|
||||
#if defined(Q_OS_ANDROID)
|
||||
const QString resourcesBinaryFile = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/resources.rcc";
|
||||
#else
|
||||
const QString resourcesBinaryFile = QCoreApplication::applicationDirPath() + "/resources.rcc";
|
||||
#endif
|
||||
const QString resourcesBinaryFile = PathUtils::getRccPath();
|
||||
if (!QFile::exists(resourcesBinaryFile)) {
|
||||
throw std::runtime_error("Unable to find primary resources");
|
||||
}
|
||||
|
@ -814,7 +811,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
throw std::runtime_error("Unable to load primary resources");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Tell the plugin manager about our statically linked plugins
|
||||
auto pluginManager = PluginManager::getInstance();
|
||||
|
@ -3670,9 +3666,21 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_1:
|
||||
case Qt::Key_2:
|
||||
case Qt::Key_3:
|
||||
case Qt::Key_1: {
|
||||
Menu* menu = Menu::getInstance();
|
||||
menu->triggerOption(MenuOption::FirstPerson);
|
||||
break;
|
||||
}
|
||||
case Qt::Key_2: {
|
||||
Menu* menu = Menu::getInstance();
|
||||
menu->triggerOption(MenuOption::FullscreenMirror);
|
||||
break;
|
||||
}
|
||||
case Qt::Key_3: {
|
||||
Menu* menu = Menu::getInstance();
|
||||
menu->triggerOption(MenuOption::ThirdPerson);
|
||||
break;
|
||||
}
|
||||
case Qt::Key_4:
|
||||
case Qt::Key_5:
|
||||
case Qt::Key_6:
|
||||
|
@ -3801,68 +3809,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
Menu::getInstance()->triggerOption(MenuOption::Chat);
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case Qt::Key_I:
|
||||
if (isShifted) {
|
||||
_myCamera.setEyeOffsetOrientation(glm::normalize(
|
||||
glm::quat(glm::vec3(0.002f, 0, 0)) * _myCamera.getEyeOffsetOrientation()));
|
||||
} else {
|
||||
_myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0, 0.001, 0));
|
||||
}
|
||||
updateProjectionMatrix();
|
||||
break;
|
||||
|
||||
case Qt::Key_K:
|
||||
if (isShifted) {
|
||||
_myCamera.setEyeOffsetOrientation(glm::normalize(
|
||||
glm::quat(glm::vec3(-0.002f, 0, 0)) * _myCamera.getEyeOffsetOrientation()));
|
||||
} else {
|
||||
_myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0, -0.001, 0));
|
||||
}
|
||||
updateProjectionMatrix();
|
||||
break;
|
||||
|
||||
case Qt::Key_J:
|
||||
if (isShifted) {
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
_viewFrustum.setFocalLength(_viewFrustum.getFocalLength() - 0.1f);
|
||||
} else {
|
||||
_myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(-0.001, 0, 0));
|
||||
}
|
||||
updateProjectionMatrix();
|
||||
break;
|
||||
|
||||
case Qt::Key_M:
|
||||
if (isShifted) {
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
_viewFrustum.setFocalLength(_viewFrustum.getFocalLength() + 0.1f);
|
||||
} else {
|
||||
_myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0.001, 0, 0));
|
||||
}
|
||||
updateProjectionMatrix();
|
||||
break;
|
||||
|
||||
case Qt::Key_U:
|
||||
if (isShifted) {
|
||||
_myCamera.setEyeOffsetOrientation(glm::normalize(
|
||||
glm::quat(glm::vec3(0, 0, -0.002f)) * _myCamera.getEyeOffsetOrientation()));
|
||||
} else {
|
||||
_myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0, 0, -0.001));
|
||||
}
|
||||
updateProjectionMatrix();
|
||||
break;
|
||||
|
||||
case Qt::Key_Y:
|
||||
if (isShifted) {
|
||||
_myCamera.setEyeOffsetOrientation(glm::normalize(
|
||||
glm::quat(glm::vec3(0, 0, 0.002f)) * _myCamera.getEyeOffsetOrientation()));
|
||||
} else {
|
||||
_myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0, 0, 0.001));
|
||||
}
|
||||
updateProjectionMatrix();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case Qt::Key_Slash:
|
||||
Menu::getInstance()->triggerOption(MenuOption::Stats);
|
||||
break;
|
||||
|
@ -4245,7 +4191,7 @@ bool Application::acceptSnapshot(const QString& urlString) {
|
|||
static uint32_t _renderedFrameIndex { INVALID_FRAME };
|
||||
|
||||
bool Application::shouldPaint() const {
|
||||
if (_aboutToQuit) {
|
||||
if (_aboutToQuit || _window->isMinimized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4805,12 +4751,15 @@ void Application::loadSettings() {
|
|||
// DONT CHECK IN
|
||||
//DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false);
|
||||
|
||||
Menu::getInstance()->loadSettings();
|
||||
auto menu = Menu::getInstance();
|
||||
menu->loadSettings();
|
||||
|
||||
// override the menu option show overlays to always be true on startup
|
||||
menu->setIsOptionChecked(MenuOption::Overlays, true);
|
||||
|
||||
// If there is a preferred plugin, we probably messed it up with the menu settings, so fix it.
|
||||
auto pluginManager = PluginManager::getInstance();
|
||||
auto plugins = pluginManager->getPreferredDisplayPlugins();
|
||||
auto menu = Menu::getInstance();
|
||||
if (plugins.size() > 0) {
|
||||
for (auto plugin : plugins) {
|
||||
if (auto action = menu->getActionForOption(plugin->getName())) {
|
||||
|
@ -7652,18 +7601,18 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa
|
|||
});
|
||||
}
|
||||
|
||||
void Application::takeSecondaryCameraSnapshot(const QString& filename) {
|
||||
postLambdaEvent([filename, this] {
|
||||
void Application::takeSecondaryCameraSnapshot(const bool& notify, const QString& filename) {
|
||||
postLambdaEvent([notify, filename, this] {
|
||||
QString snapshotPath = DependencyManager::get<Snapshot>()->saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename,
|
||||
TestScriptingInterface::getInstance()->getTestResultsLocation());
|
||||
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(snapshotPath, true);
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(snapshotPath, notify);
|
||||
});
|
||||
}
|
||||
|
||||
void Application::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename) {
|
||||
postLambdaEvent([filename, cubemapOutputFormat, cameraPosition] {
|
||||
DependencyManager::get<Snapshot>()->save360Snapshot(cameraPosition, cubemapOutputFormat, filename);
|
||||
void Application::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) {
|
||||
postLambdaEvent([notify, filename, cubemapOutputFormat, cameraPosition] {
|
||||
DependencyManager::get<Snapshot>()->save360Snapshot(cameraPosition, cubemapOutputFormat, notify, filename);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -8099,7 +8048,6 @@ void Application::switchDisplayMode() {
|
|||
setActiveDisplayPlugin(DESKTOP_DISPLAY_PLUGIN_NAME);
|
||||
startHMDStandBySession();
|
||||
}
|
||||
emit activeDisplayPluginChanged();
|
||||
}
|
||||
_previousHMDWornStatus = currentHMDWornStatus;
|
||||
}
|
||||
|
|
|
@ -281,8 +281,11 @@ public:
|
|||
float getGameLoopRate() const { return _gameLoopCounter.rate(); }
|
||||
|
||||
void takeSnapshot(bool notify, bool includeAnimated = false, float aspectRatio = 0.0f, const QString& filename = QString());
|
||||
void takeSecondaryCameraSnapshot(const QString& filename = QString());
|
||||
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename = QString());
|
||||
void takeSecondaryCameraSnapshot(const bool& notify, const QString& filename = QString());
|
||||
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition,
|
||||
const bool& cubemapOutputFormat,
|
||||
const bool& notify,
|
||||
const QString& filename = QString());
|
||||
|
||||
void shareSnapshot(const QString& filename, const QUrl& href = QUrl(""));
|
||||
|
||||
|
|
|
@ -30,9 +30,6 @@ void Application::editRenderArgs(RenderArgsEditor editor) {
|
|||
|
||||
void Application::paintGL() {
|
||||
// Some plugins process message events, allowing paintGL to be called reentrantly.
|
||||
if (_aboutToQuit || _window->isMinimized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_renderFrameCount++;
|
||||
_lastTimeRendered.start();
|
||||
|
|
|
@ -103,16 +103,32 @@ Menu::Menu() {
|
|||
editMenu->addSeparator();
|
||||
|
||||
// Edit > Cut
|
||||
addActionToQMenuAndActionHash(editMenu, "Cut", Qt::CTRL | Qt::Key_X);
|
||||
auto cutAction = addActionToQMenuAndActionHash(editMenu, "Cut", QKeySequence::Cut);
|
||||
connect(cutAction, &QAction::triggered, [] {
|
||||
QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_X, Qt::ControlModifier);
|
||||
QCoreApplication::postEvent(QCoreApplication::instance(), keyEvent);
|
||||
});
|
||||
|
||||
// Edit > Copy
|
||||
addActionToQMenuAndActionHash(editMenu, "Copy", Qt::CTRL | Qt::Key_C);
|
||||
auto copyAction = addActionToQMenuAndActionHash(editMenu, "Copy", QKeySequence::Copy);
|
||||
connect(copyAction, &QAction::triggered, [] {
|
||||
QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_C, Qt::ControlModifier);
|
||||
QCoreApplication::postEvent(QCoreApplication::instance(), keyEvent);
|
||||
});
|
||||
|
||||
// Edit > Paste
|
||||
addActionToQMenuAndActionHash(editMenu, "Paste", Qt::CTRL | Qt::Key_V);
|
||||
auto pasteAction = addActionToQMenuAndActionHash(editMenu, "Paste", QKeySequence::Paste);
|
||||
connect(pasteAction, &QAction::triggered, [] {
|
||||
QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_V, Qt::ControlModifier);
|
||||
QCoreApplication::postEvent(QCoreApplication::instance(), keyEvent);
|
||||
});
|
||||
|
||||
// Edit > Delete
|
||||
addActionToQMenuAndActionHash(editMenu, "Delete", Qt::Key_Delete);
|
||||
auto deleteAction =addActionToQMenuAndActionHash(editMenu, "Delete", QKeySequence::Delete);
|
||||
connect(deleteAction, &QAction::triggered, [] {
|
||||
QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Delete, Qt::ControlModifier);
|
||||
QCoreApplication::postEvent(QCoreApplication::instance(), keyEvent);
|
||||
});
|
||||
|
||||
editMenu->addSeparator();
|
||||
|
||||
|
@ -201,21 +217,21 @@ Menu::Menu() {
|
|||
|
||||
// View > First Person
|
||||
auto firstPersonAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
|
||||
viewMenu, MenuOption::FirstPerson, Qt::Key_1,
|
||||
viewMenu, MenuOption::FirstPerson, 0,
|
||||
true, qApp, SLOT(cameraMenuChanged())));
|
||||
|
||||
firstPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup));
|
||||
|
||||
// View > Third Person
|
||||
auto thirdPersonAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
|
||||
viewMenu, MenuOption::ThirdPerson, Qt::Key_3,
|
||||
viewMenu, MenuOption::ThirdPerson, 0,
|
||||
false, qApp, SLOT(cameraMenuChanged())));
|
||||
|
||||
thirdPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup));
|
||||
|
||||
// View > Mirror
|
||||
auto viewMirrorAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
|
||||
viewMenu, MenuOption::FullscreenMirror, Qt::Key_2,
|
||||
viewMenu, MenuOption::FullscreenMirror, 0,
|
||||
false, qApp, SLOT(cameraMenuChanged())));
|
||||
|
||||
viewMirrorAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup));
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Application.h"
|
||||
#include "SecondaryCamera.h"
|
||||
#include <TextureCache.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
#include <gpu/Context.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
using RenderArgsPointer = std::shared_ptr<RenderArgs>;
|
||||
|
||||
|
|
|
@ -654,8 +654,8 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
if (success) {
|
||||
moveOperator.addEntityToMoveList(entity, newCube);
|
||||
}
|
||||
// send an edit packet to update the entity-server about the queryAABox. If it's an
|
||||
// avatar-entity, don't.
|
||||
// send an edit packet to update the entity-server about the queryAABox
|
||||
// unless it is client-only
|
||||
if (packetSender && !entity->getClientOnly()) {
|
||||
EntityItemProperties properties = entity->getProperties();
|
||||
properties.setQueryAACubeDirty();
|
||||
|
@ -663,6 +663,17 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entity->getID(), properties);
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
|
||||
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
|
||||
if (!entityDescendant->getClientOnly() && descendant->updateQueryAACube()) {
|
||||
EntityItemProperties descendantProperties;
|
||||
descendantProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
descendantProperties.setLastEdited(now);
|
||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entityDescendant->getID(), descendantProperties);
|
||||
entityDescendant->setLastBroadcast(now); // for debug/physics status icons
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -464,7 +464,7 @@ public:
|
|||
Q_INVOKABLE bool getClearOverlayWhenMoving() const { return _clearOverlayWhenMoving; }
|
||||
/**jsdoc
|
||||
* @function MyAvatar.setClearOverlayWhenMoving
|
||||
* @returns {boolean}
|
||||
* @param {boolean} on
|
||||
*/
|
||||
Q_INVOKABLE void setClearOverlayWhenMoving(bool on) { _clearOverlayWhenMoving = on; }
|
||||
|
||||
|
|
|
@ -314,6 +314,7 @@ Wallet::Wallet() {
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
_passphrase = new QString("");
|
||||
|
||||
packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket");
|
||||
packetReceiver.registerListener(PacketType::ChallengeOwnershipRequest, this, "handleChallengeOwnershipPacket");
|
||||
|
@ -365,6 +366,10 @@ Wallet::~Wallet() {
|
|||
if (_securityImage) {
|
||||
delete _securityImage;
|
||||
}
|
||||
|
||||
if (_passphrase) {
|
||||
delete _passphrase;
|
||||
}
|
||||
}
|
||||
|
||||
bool Wallet::setPassphrase(const QString& passphrase) {
|
||||
|
@ -531,7 +536,6 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
|
|||
|
||||
// be sure to add the public key so we don't do this over and over
|
||||
_publicKeys.push_back(publicKey.toBase64());
|
||||
DependencyManager::get<WalletScriptingInterface>()->setWalletStatus((uint)WalletStatus::WALLET_STATUS_READY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ private:
|
|||
QByteArray _salt;
|
||||
QByteArray _iv;
|
||||
QByteArray _ckey;
|
||||
QString* _passphrase { new QString("") };
|
||||
QString* _passphrase { nullptr };
|
||||
bool _isOverridingServer { false };
|
||||
|
||||
bool writeWallet(const QString& newPassphrase = QString(""));
|
||||
|
|
|
@ -36,7 +36,7 @@ unsigned int PickScriptingInterface::createPick(const PickQuery::PickType type,
|
|||
* @typedef {object} Picks.RayPickProperties
|
||||
* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results.
|
||||
* @property {number} [filter=Picks.PICK_NOTHING] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
|
||||
* @property {float} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
|
||||
* @property {number} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
|
||||
* @property {string} [joint] Only for Joint or Mouse Ray Picks. If "Mouse", it will create a Ray Pick that follows the system mouse, in desktop or HMD.
|
||||
* If "Avatar", it will create a Joint Ray Pick that follows your avatar's head. Otherwise, it will create a Joint Ray Pick that follows the given joint, if it
|
||||
* exists on your current avatar.
|
||||
|
@ -103,7 +103,7 @@ unsigned int PickScriptingInterface::createRayPick(const QVariant& properties) {
|
|||
* @property {number} [hand=-1] An integer. 0 == left, 1 == right. Invalid otherwise.
|
||||
* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results.
|
||||
* @property {number} [filter=Picks.PICK_NOTHING] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
|
||||
* @property {float} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
|
||||
* @property {number} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
|
||||
*/
|
||||
unsigned int PickScriptingInterface::createStylusPick(const QVariant& properties) {
|
||||
QVariantMap propMap = properties.toMap();
|
||||
|
|
|
@ -104,7 +104,7 @@ public:
|
|||
* @property {number} type The intersection type.
|
||||
* @property {boolean} intersects If there was a valid intersection (type != INTERSECTED_NONE)
|
||||
* @property {Uuid} objectID The ID of the intersected object. Uuid.NULL for the HUD or invalid intersections.
|
||||
* @property {float} distance The distance to the intersection point from the origin of the ray.
|
||||
* @property {number} distance The distance to the intersection point from the origin of the ray.
|
||||
* @property {Vec3} intersection The intersection point in world-space.
|
||||
* @property {Vec3} surfaceNormal The surface normal at the intersected point. All NANs if type == INTERSECTED_HUD.
|
||||
* @property {Variant} extraInfo Additional intersection details when available for Model objects.
|
||||
|
@ -118,7 +118,7 @@ public:
|
|||
* @property {number} type The intersection type.
|
||||
* @property {boolean} intersects If there was a valid intersection (type != INTERSECTED_NONE)
|
||||
* @property {Uuid} objectID The ID of the intersected object. Uuid.NULL for the HUD or invalid intersections.
|
||||
* @property {float} distance The distance to the intersection point from the origin of the ray.
|
||||
* @property {number} distance The distance to the intersection point from the origin of the ray.
|
||||
* @property {Vec3} intersection The intersection point in world-space.
|
||||
* @property {Vec3} surfaceNormal The surface normal at the intersected point. All NANs if type == INTERSECTED_HUD.
|
||||
* @property {Variant} extraInfo Additional intersection details when available for Model objects.
|
||||
|
|
|
@ -136,7 +136,7 @@ public:
|
|||
* Sets the length of this Pointer. No effect on Stylus Pointers.
|
||||
* @function Pointers.setLength
|
||||
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
|
||||
* @param {float} length The desired length of the Pointer.
|
||||
* @param {number} length The desired length of the Pointer.
|
||||
*/
|
||||
Q_INVOKABLE void setLength(unsigned int uid, float length) const { DependencyManager::get<PointerManager>()->setLength(uid, length); }
|
||||
|
||||
|
|
|
@ -105,9 +105,6 @@ class ScriptEngine;
|
|||
* <li>{@link Controller.getValue|getValue}</li>
|
||||
* <li>{@link Controller.getAxisValue|getAxisValue}</li>
|
||||
* <li>{@link Controller.getPoseValue|getgetPoseValue}</li>
|
||||
* <li>{@link Controller.getButtonValue|getButtonValue} for a particular device</li>
|
||||
* <li>{@link Controller.getAxisValue(0)|getAxisValue} for a particular device</li>
|
||||
* <li>{@link Controller.getPoseValue(0)|getPoseValue} for a particular device</li>
|
||||
* <li>{@link Controller.getActionValue|getActionValue}</li>
|
||||
* </ul>
|
||||
*
|
||||
|
|
|
@ -446,12 +446,12 @@ void WindowScriptingInterface::takeSnapshot(bool notify, bool includeAnimated, f
|
|||
qApp->takeSnapshot(notify, includeAnimated, aspectRatio, filename);
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::takeSecondaryCameraSnapshot(const QString& filename) {
|
||||
qApp->takeSecondaryCameraSnapshot(filename);
|
||||
void WindowScriptingInterface::takeSecondaryCameraSnapshot(const bool& notify, const QString& filename) {
|
||||
qApp->takeSecondaryCameraSnapshot(notify, filename);
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename) {
|
||||
qApp->takeSecondaryCamera360Snapshot(cameraPosition, cubemapOutputFormat, filename);
|
||||
void WindowScriptingInterface::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) {
|
||||
qApp->takeSecondaryCamera360Snapshot(cameraPosition, cubemapOutputFormat, notify, filename);
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::shareSnapshot(const QString& path, const QUrl& href) {
|
||||
|
|
|
@ -318,7 +318,6 @@ public slots:
|
|||
* {@link Window.stillSnapshotTaken|stillSnapshotTaken} is emitted; when a still image plus moving images are captured,
|
||||
* {@link Window.processingGifStarted|processingGifStarted} and {@link Window.processingGifCompleted|processingGifCompleted}
|
||||
* are emitted. The path to store the snapshots and the length of the animated GIF to capture are specified in Settings >
|
||||
* NOTE: to provide a non-default value - all previous parameters must be provided.
|
||||
* General > Snapshots.
|
||||
* @function Window.takeSnapshot
|
||||
* @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
|
||||
|
@ -328,7 +327,7 @@ public slots:
|
|||
* @param {number} [aspectRatio=0] - The width/height ratio of the snapshot required. If the value is <code>0</code> the
|
||||
* full resolution is used (window dimensions in desktop mode; HMD display dimensions in HMD mode), otherwise one of the
|
||||
* dimensions is adjusted in order to match the aspect ratio.
|
||||
* @param {string} [filename=""] - If this parameter is not given, the image will be saved as 'hifi-snap-by-<user name>-YYYY-MM-DD_HH-MM-SS'.
|
||||
* @param {string} [filename=""] - If this parameter is not given, the image will be saved as "hifi-snap-by-<user name>-YYYY-MM-DD_HH-MM-SS".
|
||||
* If this parameter is <code>""</code> then the image will be saved as ".jpg".
|
||||
* Otherwise, the image will be saved to this filename, with an appended ".jpg".
|
||||
*
|
||||
|
@ -360,29 +359,29 @@ public slots:
|
|||
|
||||
/**jsdoc
|
||||
* Takes a still snapshot of the current view from the secondary camera that can be set up through the {@link Render} API.
|
||||
* NOTE: to provide a non-default value - all previous parameters must be provided.
|
||||
* @function Window.takeSecondaryCameraSnapshot
|
||||
* @param {string} [filename=""] - If this parameter is not given, the image will be saved as 'hifi-snap-by-<user name>-YYYY-MM-DD_HH-MM-SS'.
|
||||
* @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
|
||||
* signal.
|
||||
* @param {string} [filename=""] - If this parameter is not given, the image will be saved as "hifi-snap-by-<user name>-YYYY-MM-DD_HH-MM-SS".
|
||||
* If this parameter is <code>""</code> then the image will be saved as ".jpg".
|
||||
* Otherwise, the image will be saved to this filename, with an appended ".jpg".
|
||||
*
|
||||
* var filename = QString();
|
||||
*/
|
||||
void takeSecondaryCameraSnapshot(const QString& filename = QString());
|
||||
void takeSecondaryCameraSnapshot(const bool& notify = true, const QString& filename = QString());
|
||||
|
||||
/**jsdoc
|
||||
* Takes a 360 snapshot given a position of the secondary camera (which does not need to have been previously set up).
|
||||
* @function Window.takeSecondaryCameraSnapshot
|
||||
* @param {vec3} [cameraPosition] - The (x, y, z) position of the camera for the 360 snapshot
|
||||
* @param {boolean} [cubemapOutputFormat=false] - If <code>true</code> then the snapshot is saved as a cube map image,
|
||||
* otherwise is saved as an equirectangular image.
|
||||
* @param {string} [filename=""] - If this parameter is not given, the image will be saved as 'hifi-snap-by-<user name>-YYYY-MM-DD_HH-MM-SS'.
|
||||
* If this parameter is <code>""</code> then the image will be saved as ".jpg".
|
||||
* Otherwise, the image will be saved to this filename, with an appended ".jpg".
|
||||
*
|
||||
* var filename = QString();
|
||||
*/
|
||||
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat = false, const QString& filename = QString());
|
||||
* Takes a 360° snapshot at a given position for the secondary camera. The secondary camera does not need to have been
|
||||
* set up.
|
||||
* @function Window.takeSecondaryCamera360Snapshot
|
||||
* @param {Vec3} cameraPosition - The position of the camera for the snapshot.
|
||||
* @param {boolean} [cubemapOutputFormat=false] - If <code>true</code> then the snapshot is saved as a cube map image,
|
||||
* otherwise is saved as an equirectangular image.
|
||||
* @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
|
||||
* signal.
|
||||
* @param {string} [filename=""] - If this parameter is not supplied, the image will be saved as "hifi-snap-by-<user name>-YYYY-MM-DD_HH-MM-SS".
|
||||
* If this parameter is <code>""</code> then the image will be saved as ".jpg".
|
||||
* Otherwise, the image will be saved to this filename, with an appended ".jpg".
|
||||
*/
|
||||
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat = false, const bool& notify = true, const QString& filename = QString());
|
||||
|
||||
/**jsdoc
|
||||
* Emit a {@link Window.connectionAdded|connectionAdded} or a {@link Window.connectionError|connectionError} signal that
|
||||
|
@ -612,7 +611,8 @@ signals:
|
|||
void stillSnapshotTaken(const QString& pathStillSnapshot, bool notify);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when a still equirectangular snapshot has been taken by calling {@link Window.takeSecondaryCamera360Snapshot|takeSecondaryCamera360Snapshot}
|
||||
* Triggered when a still 360° snapshot has been taken by calling
|
||||
* {@link Window.takeSecondaryCamera360Snapshot|takeSecondaryCamera360Snapshot}.
|
||||
* @function Window.snapshot360Taken
|
||||
* @param {string} pathStillSnapshot - The path and name of the snapshot image file.
|
||||
* @param {boolean} notify - The value of the <code>notify</code> parameter that {@link Window.takeSecondaryCamera360Snapshot|takeSecondaryCamera360Snapshot}
|
||||
|
|
|
@ -122,8 +122,9 @@ static const glm::quat CAMERA_ORIENTATION_LEFT(glm::quat(glm::radians(glm::vec3(
|
|||
static const glm::quat CAMERA_ORIENTATION_BACK(glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f))));
|
||||
static const glm::quat CAMERA_ORIENTATION_RIGHT(glm::quat(glm::radians(glm::vec3(0.0f, 270.0f, 0.0f))));
|
||||
static const glm::quat CAMERA_ORIENTATION_UP(glm::quat(glm::radians(glm::vec3(90.0f, 0.0f, 0.0f))));
|
||||
void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename) {
|
||||
void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) {
|
||||
_snapshotFilename = filename;
|
||||
_notify360 = notify;
|
||||
_cubemapOutputFormat = cubemapOutputFormat;
|
||||
SecondaryCameraJobConfig* secondaryCameraRenderConfig = static_cast<SecondaryCameraJobConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera"));
|
||||
|
||||
|
@ -247,7 +248,8 @@ void Snapshot::convertToCubemap() {
|
|||
|
||||
painter.end();
|
||||
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename), true);
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename),
|
||||
_notify360);
|
||||
}
|
||||
|
||||
void Snapshot::convertToEquirectangular() {
|
||||
|
@ -327,7 +329,8 @@ void Snapshot::convertToEquirectangular() {
|
|||
}
|
||||
}
|
||||
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename), true);
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename),
|
||||
_notify360);
|
||||
}
|
||||
|
||||
QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) {
|
||||
|
|
|
@ -50,7 +50,10 @@ class Snapshot : public QObject, public Dependency {
|
|||
public:
|
||||
Snapshot();
|
||||
QString saveSnapshot(QImage image, const QString& filename, const QString& pathname = QString());
|
||||
void save360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename);
|
||||
void save360Snapshot(const glm::vec3& cameraPosition,
|
||||
const bool& cubemapOutputFormat,
|
||||
const bool& notify,
|
||||
const QString& filename);
|
||||
QTemporaryFile* saveTempSnapshot(QImage image);
|
||||
SnapshotMetaData* parseSnapshotData(QString snapshotPath);
|
||||
|
||||
|
@ -89,6 +92,7 @@ private:
|
|||
const QString& userSelectedFilename = QString(),
|
||||
const QString& userSelectedPathname = QString());
|
||||
QString _snapshotFilename;
|
||||
bool _notify360;
|
||||
bool _cubemapOutputFormat;
|
||||
QTimer _snapshotTimer;
|
||||
qint16 _snapshotIndex;
|
||||
|
|
|
@ -349,3 +349,23 @@ void Base3DOverlay::setVisible(bool visible) {
|
|||
Parent::setVisible(visible);
|
||||
notifyRenderVariableChange();
|
||||
}
|
||||
|
||||
render::ItemKey Base3DOverlay::getKey() {
|
||||
auto builder = render::ItemKey::Builder(Overlay::getKey());
|
||||
|
||||
if (getDrawInFront()) {
|
||||
builder.withLayer(render::hifi::LAYER_3D_FRONT);
|
||||
} else if (getDrawHUDLayer()) {
|
||||
builder.withLayer(render::hifi::LAYER_3D_HUD);
|
||||
} else {
|
||||
builder.withoutLayer();
|
||||
}
|
||||
|
||||
builder.withoutViewSpace();
|
||||
|
||||
if (isTransparent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
|
@ -35,6 +35,7 @@ public:
|
|||
// getters
|
||||
virtual bool is3D() const override { return true; }
|
||||
|
||||
virtual render::ItemKey getKey() override;
|
||||
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override { subItems.push_back(getRenderItemID()); return (uint32_t) subItems.size(); }
|
||||
virtual scriptable::ScriptableModelBase getScriptableModel() override { return scriptable::ScriptableModelBase(); }
|
||||
|
||||
|
|
|
@ -115,6 +115,10 @@ void ModelOverlay::update(float deltatime) {
|
|||
_drawInHUDDirty = false;
|
||||
_model->setLayeredInHUD(getDrawHUDLayer(), scene);
|
||||
}
|
||||
if (_groupCulledDirty) {
|
||||
_groupCulledDirty = false;
|
||||
_model->setGroupCulled(_isGroupCulled);
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
|
||||
if (!_texturesLoaded && _model->getGeometry() && _model->getGeometry()->areTexturesLoaded()) {
|
||||
|
@ -149,13 +153,24 @@ void ModelOverlay::setVisible(bool visible) {
|
|||
}
|
||||
|
||||
void ModelOverlay::setDrawInFront(bool drawInFront) {
|
||||
Base3DOverlay::setDrawInFront(drawInFront);
|
||||
_drawInFrontDirty = true;
|
||||
if (drawInFront != getDrawInFront()) {
|
||||
Base3DOverlay::setDrawInFront(drawInFront);
|
||||
_drawInFrontDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelOverlay::setDrawHUDLayer(bool drawHUDLayer) {
|
||||
Base3DOverlay::setDrawHUDLayer(drawHUDLayer);
|
||||
_drawInHUDDirty = true;
|
||||
if (drawHUDLayer != getDrawHUDLayer()) {
|
||||
Base3DOverlay::setDrawHUDLayer(drawHUDLayer);
|
||||
_drawInHUDDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelOverlay::setGroupCulled(bool groupCulled) {
|
||||
if (groupCulled != _isGroupCulled) {
|
||||
_isGroupCulled = groupCulled;
|
||||
_groupCulledDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelOverlay::setProperties(const QVariantMap& properties) {
|
||||
|
@ -210,6 +225,11 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
|
|||
Q_ARG(const QVariantMap&, textureMap));
|
||||
}
|
||||
|
||||
auto groupCulledValue = properties["isGroupCulled"];
|
||||
if (groupCulledValue.isValid() && groupCulledValue.canConvert(QVariant::Bool)) {
|
||||
setGroupCulled(groupCulledValue.toBool());
|
||||
}
|
||||
|
||||
// jointNames is read-only.
|
||||
// jointPositions is read-only.
|
||||
// jointOrientations is read-only.
|
||||
|
@ -347,6 +367,8 @@ vectorType ModelOverlay::mapJoints(mapFunction<itemType> function) const {
|
|||
* {@link Overlays.findRayIntersection|findRayIntersection} ignores the overlay.
|
||||
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
|
||||
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
|
||||
* @property {boolean} isGroupCulled=false - If <code>true</code>, the mesh parts of the model are LOD culled as a group.
|
||||
* If <code>false</code>, separate mesh parts will be LOD culled individually.
|
||||
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
|
||||
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
|
||||
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
|
||||
|
@ -711,3 +733,11 @@ scriptable::ScriptableModelBase ModelOverlay::getScriptableModel() {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
render::ItemKey ModelOverlay::getKey() {
|
||||
auto builder = render::ItemKey::Builder(Base3DOverlay::getKey());
|
||||
if (_isGroupCulled) {
|
||||
builder.withMetaCullGroup();
|
||||
}
|
||||
return builder.build();
|
||||
}
|
|
@ -33,6 +33,7 @@ public:
|
|||
|
||||
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override;
|
||||
|
||||
render::ItemKey getKey() override;
|
||||
void clearSubRenderItemIDs();
|
||||
void setSubRenderItemIDs(const render::ItemIDs& ids);
|
||||
|
||||
|
@ -63,6 +64,7 @@ public:
|
|||
void setVisible(bool visible) override;
|
||||
void setDrawInFront(bool drawInFront) override;
|
||||
void setDrawHUDLayer(bool drawHUDLayer) override;
|
||||
void setGroupCulled(bool groupCulled);
|
||||
|
||||
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override;
|
||||
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override;
|
||||
|
@ -121,6 +123,8 @@ private:
|
|||
bool _visibleDirty { true };
|
||||
bool _drawInFrontDirty { false };
|
||||
bool _drawInHUDDirty { false };
|
||||
bool _isGroupCulled { false };
|
||||
bool _groupCulledDirty { false };
|
||||
|
||||
void processMaterials();
|
||||
|
||||
|
|
|
@ -244,4 +244,21 @@ void Overlay::addMaterial(graphics::MaterialLayer material, const std::string& p
|
|||
void Overlay::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||
_materials[parentMaterialName].remove(material);
|
||||
}
|
||||
|
||||
render::ItemKey Overlay::getKey() {
|
||||
auto builder = render::ItemKey::Builder().withTypeShape();
|
||||
|
||||
builder.withViewSpace();
|
||||
builder.withLayer(render::hifi::LAYER_2D);
|
||||
|
||||
if (!getVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
// always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view
|
||||
render::hifi::Tag viewTagBits = getIsVisibleInSecondaryCamera() ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW;
|
||||
builder.withTagBits(viewTagBits);
|
||||
|
||||
return builder.build();
|
||||
}
|
|
@ -40,6 +40,7 @@ public:
|
|||
virtual void update(float deltatime) {}
|
||||
virtual void render(RenderArgs* args) = 0;
|
||||
|
||||
virtual render::ItemKey getKey();
|
||||
virtual AABox getBounds() const = 0;
|
||||
virtual bool supportsGetProperty() const { return true; }
|
||||
|
||||
|
|
|
@ -32,34 +32,7 @@
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay) {
|
||||
auto builder = ItemKey::Builder().withTypeShape();
|
||||
if (overlay->is3D()) {
|
||||
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
|
||||
if (overlay3D->getDrawInFront()) {
|
||||
builder.withLayer(render::hifi::LAYER_3D_FRONT);
|
||||
} else if (overlay3D->getDrawHUDLayer()) {
|
||||
builder.withLayer(render::hifi::LAYER_3D_HUD);
|
||||
}
|
||||
|
||||
if (overlay->isTransparent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
} else {
|
||||
builder.withViewSpace();
|
||||
builder.withLayer(render::hifi::LAYER_2D);
|
||||
}
|
||||
|
||||
if (!overlay->getVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
// always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view
|
||||
uint32_t viewTagBits = render::hifi::TAG_MAIN_VIEW |
|
||||
(overlay->getIsVisibleInSecondaryCamera() ? render::hifi::TAG_SECONDARY_VIEW : render::hifi::TAG_NONE);
|
||||
|
||||
builder.withTagBits(viewTagBits);
|
||||
|
||||
return builder.build();
|
||||
return overlay->getKey();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
|
||||
return overlay->getBounds();
|
||||
|
|
|
@ -92,28 +92,16 @@ namespace controller {
|
|||
return userInputMapper->getValue(Input((uint32_t)source));
|
||||
}
|
||||
|
||||
float ScriptingInterface::getButtonValue(StandardButtonChannel source, uint16_t device) const {
|
||||
return getValue(Input(device, source, ChannelType::BUTTON).getID());
|
||||
}
|
||||
|
||||
float ScriptingInterface::getAxisValue(int source) const {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
return userInputMapper->getValue(Input((uint32_t)source));
|
||||
}
|
||||
|
||||
float ScriptingInterface::getAxisValue(StandardAxisChannel source, uint16_t device) const {
|
||||
return getValue(Input(device, source, ChannelType::AXIS).getID());
|
||||
}
|
||||
|
||||
Pose ScriptingInterface::getPoseValue(const int& source) const {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
return userInputMapper->getPose(Input((uint32_t)source));
|
||||
}
|
||||
|
||||
Pose ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
|
||||
return getPoseValue(Input(device, source, ChannelType::POSE).getID());
|
||||
}
|
||||
|
||||
QVector<Action> ScriptingInterface::getAllActions() {
|
||||
return DependencyManager::get<UserInputMapper>()->getAllActions();
|
||||
}
|
||||
|
|
|
@ -206,43 +206,6 @@ namespace controller {
|
|||
*/
|
||||
Q_INVOKABLE Pose getPoseValue(const int& source) const;
|
||||
|
||||
/**jsdoc
|
||||
* Get the value of a button on a particular device.
|
||||
* @function Controller.getButtonValue
|
||||
* @param {StandardButtonChannel} source - The button to get the value of.
|
||||
* @param {number} [device=0] - The ID of the hardware device to get the value from. The default value of
|
||||
* <code>0</code> corresponds to <code>Standard</code>.
|
||||
* @returns {number} The current value of the button if the parameters are valid, otherwise <code>0</code>.
|
||||
* @deprecated This function no longer works.
|
||||
*/
|
||||
// FIXME: This function causes a JavaScript crash: https://highfidelity.manuscript.com/f/cases/edit/14139
|
||||
Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const;
|
||||
|
||||
/**jsdoc
|
||||
* Get the value of an axis control on a particular device.
|
||||
* @function Controller.getAxisValue
|
||||
* @variation 0
|
||||
* @param {StandardAxisChannel} source - The axis to get the value of.
|
||||
* @param {number} [device=0] - The ID of the hardware device to get the value from. The default value of
|
||||
* <code>0</code> corresponds to <code>Standard</code>.
|
||||
* @returns {number} The current value of the axis if the parameters are valid, otherwise <code>0</code>.
|
||||
* @deprecated This function no longer works.
|
||||
*/
|
||||
Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const;
|
||||
|
||||
/**jsdoc
|
||||
* Get the value of an pose control on a particular device.
|
||||
* @function Controller.getPoseValue
|
||||
* @variation 0
|
||||
* @param {StandardPoseChannel} source - The pose to get the value of.
|
||||
* @param {number} [device=0] - The ID of the hardware device to get the value from. The default value of
|
||||
* <code>0</code> corresponds to <code>Standard</code>.
|
||||
* @returns {Pose} The current value of the controller pose output if the parameters are valid, otherwise an invalid
|
||||
* pose with <code>Pose.valid == false</code>.
|
||||
* @deprecated This function no longer works.
|
||||
*/
|
||||
Q_INVOKABLE Pose getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
|
||||
|
||||
/**jsdoc
|
||||
* Triggers a haptic pulse on connected and enabled devices that have the capability.
|
||||
* @function Controller.triggerHapticPulse
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "HTTPConnection.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QCryptographicHash>
|
||||
#include <QTcpSocket>
|
||||
|
@ -29,11 +31,92 @@ const char* HTTPConnection::StatusCode404 = "404 Not Found";
|
|||
const char* HTTPConnection::StatusCode500 = "500 Internal server error";
|
||||
const char* HTTPConnection::DefaultContentType = "text/plain; charset=ISO-8859-1";
|
||||
|
||||
HTTPConnection::HTTPConnection (QTcpSocket* socket, HTTPManager* parentManager) :
|
||||
|
||||
class MemoryStorage : public HTTPConnection::Storage {
|
||||
public:
|
||||
static std::unique_ptr<MemoryStorage> make(qint64 size);
|
||||
virtual ~MemoryStorage() = default;
|
||||
|
||||
const QByteArray& content() const override { return _array; }
|
||||
qint64 bytesLeftToWrite() const override { return _array.size() - _bytesWritten; }
|
||||
void write(const QByteArray& data) override;
|
||||
|
||||
private:
|
||||
MemoryStorage(qint64 size) { _array.resize(size); }
|
||||
|
||||
QByteArray _array;
|
||||
qint64 _bytesWritten { 0 };
|
||||
};
|
||||
|
||||
std::unique_ptr<MemoryStorage> MemoryStorage::make(qint64 size) {
|
||||
return std::unique_ptr<MemoryStorage>(new MemoryStorage(size));
|
||||
}
|
||||
|
||||
void MemoryStorage::write(const QByteArray& data) {
|
||||
assert(data.size() <= bytesLeftToWrite());
|
||||
memcpy(_array.data() + _bytesWritten, data.data(), data.size());
|
||||
_bytesWritten += data.size();
|
||||
}
|
||||
|
||||
|
||||
class FileStorage : public HTTPConnection::Storage {
|
||||
public:
|
||||
static std::unique_ptr<FileStorage> make(qint64 size);
|
||||
virtual ~FileStorage();
|
||||
|
||||
const QByteArray& content() const override { return _wrapperArray; };
|
||||
qint64 bytesLeftToWrite() const override { return _mappedMemorySize - _bytesWritten; }
|
||||
void write(const QByteArray& data) override;
|
||||
|
||||
private:
|
||||
FileStorage(std::unique_ptr<QTemporaryFile> file, uchar* mapped, qint64 size);
|
||||
|
||||
// Byte array is const because any edit will trigger a deep copy
|
||||
// and pull all the data we want to keep on disk in memory.
|
||||
const QByteArray _wrapperArray;
|
||||
std::unique_ptr<QTemporaryFile> _file;
|
||||
|
||||
uchar* const _mappedMemoryAddress { nullptr };
|
||||
const qint64 _mappedMemorySize { 0 };
|
||||
qint64 _bytesWritten { 0 };
|
||||
};
|
||||
|
||||
std::unique_ptr<FileStorage> FileStorage::make(qint64 size) {
|
||||
auto file = std::unique_ptr<QTemporaryFile>(new QTemporaryFile());
|
||||
file->open(); // Open for resize
|
||||
file->resize(size);
|
||||
auto mapped = file->map(0, size); // map the entire file
|
||||
|
||||
return std::unique_ptr<FileStorage>(new FileStorage(std::move(file), mapped, size));
|
||||
}
|
||||
|
||||
// Use QByteArray::fromRawData to avoid a new allocation and access the already existing
|
||||
// memory directly as long as all operations on the array are const.
|
||||
FileStorage::FileStorage(std::unique_ptr<QTemporaryFile> file, uchar* mapped, qint64 size) :
|
||||
_wrapperArray(QByteArray::fromRawData(reinterpret_cast<char*>(mapped), size)),
|
||||
_file(std::move(file)),
|
||||
_mappedMemoryAddress(mapped),
|
||||
_mappedMemorySize(size)
|
||||
{
|
||||
}
|
||||
|
||||
FileStorage::~FileStorage() {
|
||||
_file->unmap(_mappedMemoryAddress);
|
||||
_file->close();
|
||||
}
|
||||
|
||||
void FileStorage::write(const QByteArray& data) {
|
||||
assert(data.size() <= bytesLeftToWrite());
|
||||
// We write directly to the mapped memory
|
||||
memcpy(_mappedMemoryAddress + _bytesWritten, data.data(), data.size());
|
||||
_bytesWritten += data.size();
|
||||
}
|
||||
|
||||
|
||||
HTTPConnection::HTTPConnection(QTcpSocket* socket, HTTPManager* parentManager) :
|
||||
QObject(parentManager),
|
||||
_parentManager(parentManager),
|
||||
_socket(socket),
|
||||
_stream(socket),
|
||||
_address(socket->peerAddress())
|
||||
{
|
||||
// take over ownership of the socket
|
||||
|
@ -62,7 +145,7 @@ QHash<QString, QString> HTTPConnection::parseUrlEncodedForm() {
|
|||
return QHash<QString, QString>();
|
||||
}
|
||||
|
||||
QUrlQuery form { _requestContent };
|
||||
QUrlQuery form { _requestContent->content() };
|
||||
QHash<QString, QString> pairs;
|
||||
for (auto pair : form.queryItems()) {
|
||||
auto key = QUrl::fromPercentEncoding(pair.first.toLatin1().replace('+', ' '));
|
||||
|
@ -97,7 +180,7 @@ QList<FormData> HTTPConnection::parseFormData() const {
|
|||
QByteArray end = "\r\n--" + boundary + "--\r\n";
|
||||
|
||||
QList<FormData> data;
|
||||
QBuffer buffer(const_cast<QByteArray*>(&_requestContent));
|
||||
QBuffer buffer(const_cast<QByteArray*>(&_requestContent->content()));
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
while (buffer.canReadLine()) {
|
||||
QByteArray line = buffer.readLine().trimmed();
|
||||
|
@ -107,12 +190,13 @@ QList<FormData> HTTPConnection::parseFormData() const {
|
|||
QByteArray line = buffer.readLine().trimmed();
|
||||
if (line.isEmpty()) {
|
||||
// content starts after this line
|
||||
int idx = _requestContent.indexOf(end, buffer.pos());
|
||||
int idx = _requestContent->content().indexOf(end, buffer.pos());
|
||||
if (idx == -1) {
|
||||
qWarning() << "Missing end boundary." << _address;
|
||||
return data;
|
||||
}
|
||||
datum.second = _requestContent.mid(buffer.pos(), idx - buffer.pos());
|
||||
datum.second = QByteArray::fromRawData(_requestContent->content().data() + buffer.pos(),
|
||||
idx - buffer.pos());
|
||||
data.append(datum);
|
||||
buffer.seek(idx + end.length());
|
||||
|
||||
|
@ -256,7 +340,24 @@ void HTTPConnection::readHeaders() {
|
|||
_parentManager->handleHTTPRequest(this, _requestUrl);
|
||||
|
||||
} else {
|
||||
_requestContent.resize(clength.toInt());
|
||||
bool success = false;
|
||||
auto length = clength.toInt(&success);
|
||||
if (!success) {
|
||||
qWarning() << "Invalid header." << _address << trimmed;
|
||||
respond("400 Bad Request", "The header was malformed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Storing big requests in memory gets expensive, especially on servers
|
||||
// with limited memory. So we store big requests in a temporary file on disk
|
||||
// and map it to faster read/write access.
|
||||
static const int MAX_CONTENT_SIZE_IN_MEMORY = 10 * 1000 * 1000;
|
||||
if (length < MAX_CONTENT_SIZE_IN_MEMORY) {
|
||||
_requestContent = MemoryStorage::make(length);
|
||||
} else {
|
||||
_requestContent = FileStorage::make(length);
|
||||
}
|
||||
|
||||
connect(_socket, SIGNAL(readyRead()), SLOT(readContent()));
|
||||
|
||||
// read any content immediately available
|
||||
|
@ -285,12 +386,13 @@ void HTTPConnection::readHeaders() {
|
|||
}
|
||||
|
||||
void HTTPConnection::readContent() {
|
||||
int size = _requestContent.size();
|
||||
if (_socket->bytesAvailable() < size) {
|
||||
return;
|
||||
}
|
||||
_socket->read(_requestContent.data(), size);
|
||||
_socket->disconnect(this, SLOT(readContent()));
|
||||
auto size = std::min(_socket->bytesAvailable(), _requestContent->bytesLeftToWrite());
|
||||
|
||||
_parentManager->handleHTTPRequest(this, _requestUrl.path());
|
||||
_requestContent->write(_socket->read(size));
|
||||
|
||||
if (_requestContent->bytesLeftToWrite() == 0) {
|
||||
_socket->disconnect(this, SLOT(readContent()));
|
||||
|
||||
_parentManager->handleHTTPRequest(this, _requestUrl.path());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,14 @@
|
|||
#ifndef hifi_HTTPConnection_h
|
||||
#define hifi_HTTPConnection_h
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QHash>
|
||||
#include <QtNetwork/QHostAddress>
|
||||
#include <QIODevice>
|
||||
#include <QList>
|
||||
#include <QtNetwork/QHostAddress>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QTemporaryFile>
|
||||
#include <QUrl>
|
||||
|
||||
#include <memory>
|
||||
|
@ -57,52 +57,63 @@ public:
|
|||
/// WebSocket close status codes.
|
||||
enum ReasonCode { NoReason = 0, NormalClosure = 1000, GoingAway = 1001 };
|
||||
|
||||
class Storage {
|
||||
public:
|
||||
Storage() = default;
|
||||
virtual ~Storage() = default;
|
||||
|
||||
virtual const QByteArray& content() const = 0;
|
||||
|
||||
virtual qint64 bytesLeftToWrite() const = 0;
|
||||
virtual void write(const QByteArray& data) = 0;
|
||||
};
|
||||
|
||||
/// Initializes the connection.
|
||||
HTTPConnection (QTcpSocket* socket, HTTPManager* parentManager);
|
||||
HTTPConnection(QTcpSocket* socket, HTTPManager* parentManager);
|
||||
|
||||
/// Destroys the connection.
|
||||
virtual ~HTTPConnection ();
|
||||
virtual ~HTTPConnection();
|
||||
|
||||
/// Returns a pointer to the underlying socket, to which WebSocket message bodies should be written.
|
||||
QTcpSocket* socket () const { return _socket; }
|
||||
QTcpSocket* socket() const { return _socket; }
|
||||
|
||||
/// Returns the request operation.
|
||||
QNetworkAccessManager::Operation requestOperation () const { return _requestOperation; }
|
||||
QNetworkAccessManager::Operation requestOperation() const { return _requestOperation; }
|
||||
|
||||
/// Returns a reference to the request URL.
|
||||
const QUrl& requestUrl () const { return _requestUrl; }
|
||||
const QUrl& requestUrl() const { return _requestUrl; }
|
||||
|
||||
/// Returns a copy of the request header value. If it does not exist, it will return a default constructed QByteArray.
|
||||
QByteArray requestHeader(const QString& key) const { return _requestHeaders.value(key.toLower().toLocal8Bit()); }
|
||||
|
||||
/// Returns a reference to the request content.
|
||||
const QByteArray& requestContent () const { return _requestContent; }
|
||||
const QByteArray& requestContent() const { return _requestContent->content(); }
|
||||
|
||||
/// Parses the request content as form data, returning a list of header/content pairs.
|
||||
QList<FormData> parseFormData () const;
|
||||
QList<FormData> parseFormData() const;
|
||||
|
||||
/// Parses the request content as a url encoded form, returning a hash of key/value pairs.
|
||||
/// Duplicate keys are not supported.
|
||||
QHash<QString, QString> parseUrlEncodedForm();
|
||||
|
||||
/// Sends a response and closes the connection.
|
||||
void respond (const char* code, const QByteArray& content = QByteArray(),
|
||||
void respond(const char* code, const QByteArray& content = QByteArray(),
|
||||
const char* contentType = DefaultContentType,
|
||||
const Headers& headers = Headers());
|
||||
void respond (const char* code, std::unique_ptr<QIODevice> device,
|
||||
void respond(const char* code, std::unique_ptr<QIODevice> device,
|
||||
const char* contentType = DefaultContentType,
|
||||
const Headers& headers = Headers());
|
||||
|
||||
protected slots:
|
||||
|
||||
/// Reads the request line.
|
||||
void readRequest ();
|
||||
void readRequest();
|
||||
|
||||
/// Reads the headers.
|
||||
void readHeaders ();
|
||||
void readHeaders();
|
||||
|
||||
/// Reads the content.
|
||||
void readContent ();
|
||||
void readContent();
|
||||
|
||||
protected:
|
||||
void respondWithStatusAndHeaders(const char* code, const char* contentType, const Headers& headers, qint64 size);
|
||||
|
@ -112,9 +123,6 @@ protected:
|
|||
|
||||
/// The underlying socket.
|
||||
QTcpSocket* _socket;
|
||||
|
||||
/// The data stream for writing to the socket.
|
||||
QDataStream _stream;
|
||||
|
||||
/// The stored address.
|
||||
QHostAddress _address;
|
||||
|
@ -132,7 +140,7 @@ protected:
|
|||
QByteArray _lastRequestHeader;
|
||||
|
||||
/// The content of the request.
|
||||
QByteArray _requestContent;
|
||||
std::unique_ptr<Storage> _requestContent;
|
||||
|
||||
/// Response content
|
||||
std::unique_ptr<QIODevice> _responseDevice;
|
||||
|
|
|
@ -24,8 +24,7 @@
|
|||
const int SOCKET_ERROR_EXIT_CODE = 2;
|
||||
const int SOCKET_CHECK_INTERVAL_IN_MS = 30000;
|
||||
|
||||
HTTPManager::HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) :
|
||||
QTcpServer(parent),
|
||||
HTTPManager::HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler) :
|
||||
_listenAddress(listenAddress),
|
||||
_documentRoot(documentRoot),
|
||||
_requestHandler(requestHandler),
|
||||
|
|
|
@ -33,7 +33,7 @@ class HTTPManager : public QTcpServer, public HTTPRequestHandler {
|
|||
Q_OBJECT
|
||||
public:
|
||||
/// Initializes the manager.
|
||||
HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0);
|
||||
HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = nullptr);
|
||||
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
|
||||
|
||||
|
|
|
@ -23,4 +23,4 @@ protected slots:
|
|||
void handleSSLErrors(const QList<QSslError>& errors);
|
||||
};
|
||||
|
||||
#endif // hifi_HTTPSConnection_h
|
||||
#endif // hifi_HTTPSConnection_h
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
#include "HTTPSConnection.h"
|
||||
|
||||
HTTPSManager::HTTPSManager(QHostAddress listenAddress, quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey,
|
||||
const QString& documentRoot, HTTPSRequestHandler* requestHandler, QObject* parent) :
|
||||
HTTPManager(listenAddress, port, documentRoot, requestHandler, parent),
|
||||
const QString& documentRoot, HTTPSRequestHandler* requestHandler) :
|
||||
HTTPManager(listenAddress, port, documentRoot, requestHandler),
|
||||
_certificate(certificate),
|
||||
_privateKey(privateKey),
|
||||
_sslRequestHandler(requestHandler)
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
const QSslCertificate& certificate,
|
||||
const QSslKey& privateKey,
|
||||
const QString& documentRoot,
|
||||
HTTPSRequestHandler* requestHandler = NULL, QObject* parent = 0);
|
||||
HTTPSRequestHandler* requestHandler = nullptr);
|
||||
|
||||
void setCertificate(const QSslCertificate& certificate) { _certificate = certificate; }
|
||||
void setPrivateKey(const QSslKey& privateKey) { _privateKey = privateKey; }
|
||||
|
@ -48,4 +48,4 @@ private:
|
|||
HTTPSRequestHandler* _sslRequestHandler;
|
||||
};
|
||||
|
||||
#endif // hifi_HTTPSManager_h
|
||||
#endif // hifi_HTTPSManager_h
|
||||
|
|
|
@ -157,16 +157,20 @@ Item::Bound EntityRenderer::getBound() {
|
|||
return _bound;
|
||||
}
|
||||
|
||||
render::hifi::Tag EntityRenderer::getTagMask() const {
|
||||
return _isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW;
|
||||
}
|
||||
|
||||
ItemKey EntityRenderer::getKey() {
|
||||
if (isTransparent()) {
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask());
|
||||
}
|
||||
|
||||
// This allows shapes to cast shadows
|
||||
if (_canCastShadow) {
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).withShadowCaster();
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()).withShadowCaster();
|
||||
} else {
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,6 +384,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
|
|||
|
||||
_moving = entity->isMovingRelativeToParent();
|
||||
_visible = entity->getVisible();
|
||||
setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
|
||||
_canCastShadow = entity->getCanCastShadow();
|
||||
_cauterized = entity->getCauterized();
|
||||
_needsRenderUpdate = false;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "AbstractViewStateInterface.h"
|
||||
#include "EntitiesRendererLogging.h"
|
||||
#include <graphics-scripting/Forward.h>
|
||||
#include <RenderHifi.h>
|
||||
|
||||
class EntityTreeRenderer;
|
||||
|
||||
|
@ -74,6 +75,7 @@ protected:
|
|||
virtual Item::Bound getBound() override;
|
||||
virtual void render(RenderArgs* args) override final;
|
||||
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override;
|
||||
virtual render::hifi::Tag getTagMask() const;
|
||||
|
||||
// Returns true if the item in question needs to have updateInScene called because of internal rendering state changes
|
||||
virtual bool needsRenderUpdate() const;
|
||||
|
@ -97,6 +99,8 @@ protected:
|
|||
bool isFading() const { return _isFading; }
|
||||
virtual bool isTransparent() const { return _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f : false; }
|
||||
inline bool isValidRenderItem() const { return _renderItemID != Item::INVALID_ITEM_ID; }
|
||||
|
||||
virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; }
|
||||
|
||||
template <typename F, typename T>
|
||||
T withReadLockResult(const std::function<T()>& f) {
|
||||
|
@ -129,6 +133,7 @@ protected:
|
|||
bool _isFading{ _entitiesShouldFadeFunction() };
|
||||
bool _prevIsTransparent { false };
|
||||
bool _visible { false };
|
||||
bool _isVisibleInSecondaryCamera { false };
|
||||
bool _canCastShadow { false };
|
||||
bool _cauterized { false };
|
||||
bool _moving { false };
|
||||
|
|
|
@ -43,7 +43,7 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
|
|||
|
||||
ItemKey MaterialEntityRenderer::getKey() {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
builder.withTypeShape().withTagBits(getTagMask());
|
||||
|
||||
if (!_visible) {
|
||||
builder.withInvisible();
|
||||
|
|
|
@ -1060,9 +1060,9 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
|
|||
|
||||
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
|
||||
if (didVisualGeometryRequestSucceed) {
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask());
|
||||
} else {
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(getTagMask());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1070,6 +1070,13 @@ ItemKey ModelEntityRenderer::getKey() {
|
|||
return _itemKey;
|
||||
}
|
||||
|
||||
render::hifi::Tag ModelEntityRenderer::getTagMask() const {
|
||||
// Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
|
||||
return _cauterized ?
|
||||
(_isVisibleInSecondaryCamera ? render::hifi::TAG_SECONDARY_VIEW : render::hifi::TAG_NONE) :
|
||||
Parent::getTagMask(); // calculate which views to be shown in
|
||||
}
|
||||
|
||||
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
|
||||
if (_model) {
|
||||
auto metaSubItems = _subRenderItemIDs;
|
||||
|
@ -1329,6 +1336,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
emit DependencyManager::get<scriptable::ModelProviderFactory>()->
|
||||
modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, _model);
|
||||
}
|
||||
_didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed;
|
||||
});
|
||||
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
|
||||
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
|
||||
|
@ -1386,11 +1394,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
entity->updateModelBounds();
|
||||
entity->stopModelOverrideIfNoParent();
|
||||
|
||||
// Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
|
||||
auto tagMask = _cauterized ?
|
||||
render::hifi::TAG_SECONDARY_VIEW : // draw in every view except the main one (view zero)
|
||||
render::hifi::TAG_ALL_VIEWS; // draw in all views
|
||||
|
||||
render::hifi::Tag tagMask = getTagMask();
|
||||
if (model->isVisible() != _visible) {
|
||||
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
||||
// the renderable item. As it stands now the model checks it's visible/invisible state
|
||||
|
@ -1478,6 +1482,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) {
|
||||
Parent::setIsVisibleInSecondaryCamera(value);
|
||||
setKey(_didLastVisualGeometryRequestSucceed);
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::flagForCollisionGeometryUpdate() {
|
||||
_needsCollisionGeometryUpdate = true;
|
||||
emit requestRenderUpdate();
|
||||
|
|
|
@ -164,6 +164,10 @@ protected:
|
|||
void flagForCollisionGeometryUpdate();
|
||||
void setCollisionMeshKey(const void* key);
|
||||
|
||||
render::hifi::Tag getTagMask() const override;
|
||||
|
||||
void setIsVisibleInSecondaryCamera(bool value) override;
|
||||
|
||||
private:
|
||||
void animate(const TypedEntityPointer& entity);
|
||||
void mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames);
|
||||
|
@ -202,6 +206,8 @@ private:
|
|||
|
||||
render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() };
|
||||
|
||||
bool _didLastVisualGeometryRequestSucceed { true };
|
||||
|
||||
void processMaterials();
|
||||
};
|
||||
|
||||
|
|
|
@ -147,9 +147,9 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn
|
|||
|
||||
ItemKey ParticleEffectEntityRenderer::getKey() {
|
||||
if (_visible) {
|
||||
return ItemKey::Builder::transparentShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
return ItemKey::Builder::transparentShape().withTagBits(getTagMask());
|
||||
} else {
|
||||
return ItemKey::Builder().withInvisible().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
|
||||
return ItemKey::Builder().withInvisible().withTagBits(getTagMask()).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
|
|||
}
|
||||
|
||||
ItemKey PolyLineEntityRenderer::getKey() {
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask());
|
||||
}
|
||||
|
||||
ShapeKey PolyLineEntityRenderer::getShapeKey() {
|
||||
|
|
|
@ -169,7 +169,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
virtual ItemKey getKey() override { return ItemKey::Builder::opaqueShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); }
|
||||
virtual ItemKey getKey() override { return ItemKey::Builder::opaqueShape().withTagBits(getTagMask()); }
|
||||
virtual ShapeKey getShapeKey() override;
|
||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||
|
|
|
@ -139,7 +139,7 @@ bool ShapeEntityRenderer::isTransparent() const {
|
|||
|
||||
ItemKey ShapeEntityRenderer::getKey() {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
builder.withTypeShape().withTypeMeta().withTagBits(getTagMask());
|
||||
|
||||
withReadLock([&] {
|
||||
if (isTransparent()) {
|
||||
|
|
|
@ -269,7 +269,7 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
|||
|
||||
|
||||
ItemKey ZoneEntityRenderer::getKey() {
|
||||
return ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
|
||||
return ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).build();
|
||||
}
|
||||
|
||||
bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||
|
|
|
@ -1383,6 +1383,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(canCastShadow, setCanCastShadow);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(isVisibleInSecondaryCamera, setIsVisibleInSecondaryCamera);
|
||||
|
||||
// Certifiable Properties
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemName, setItemName);
|
||||
|
@ -2760,6 +2761,28 @@ void EntityItem::setVisible(bool value) {
|
|||
}
|
||||
}
|
||||
|
||||
bool EntityItem::isVisibleInSecondaryCamera() const {
|
||||
bool result;
|
||||
withReadLock([&] {
|
||||
result = _isVisibleInSecondaryCamera;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setIsVisibleInSecondaryCamera(bool value) {
|
||||
bool changed = false;
|
||||
withWriteLock([&] {
|
||||
if (_isVisibleInSecondaryCamera != value) {
|
||||
changed = true;
|
||||
_isVisibleInSecondaryCamera = value;
|
||||
}
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
emit requestRenderUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
bool EntityItem::getCanCastShadow() const {
|
||||
bool result;
|
||||
withReadLock([&] {
|
||||
|
|
|
@ -277,6 +277,9 @@ public:
|
|||
bool getVisible() const;
|
||||
void setVisible(bool value);
|
||||
|
||||
bool isVisibleInSecondaryCamera() const;
|
||||
void setIsVisibleInSecondaryCamera(bool value);
|
||||
|
||||
bool getCanCastShadow() const;
|
||||
void setCanCastShadow(bool value);
|
||||
|
||||
|
@ -578,6 +581,7 @@ protected:
|
|||
glm::vec3 _registrationPoint { ENTITY_ITEM_DEFAULT_REGISTRATION_POINT };
|
||||
float _angularDamping { ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING };
|
||||
bool _visible { ENTITY_ITEM_DEFAULT_VISIBLE };
|
||||
bool _isVisibleInSecondaryCamera { ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA };
|
||||
bool _canCastShadow{ ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW };
|
||||
bool _collisionless { ENTITY_ITEM_DEFAULT_COLLISIONLESS };
|
||||
uint16_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT };
|
||||
|
|
|
@ -368,6 +368,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_DATA, materialData);
|
||||
CHECK_PROPERTY_CHANGE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera);
|
||||
|
||||
// Certifiable Properties
|
||||
CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName);
|
||||
|
@ -490,6 +491,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* {@link Entities.EntityType|Model} and {@link Entities.EntityType|Shape} entities. Shadows are cast if inside a
|
||||
* {@link Entities.EntityType|Zone} entity with <code>castShadows</code> enabled in its
|
||||
* {@link Entities.EntityProperties-Zone|keyLight} property.
|
||||
* @property {boolean} isVisibleInSecondaryCamera=true - Whether or not the entity is rendered in the secondary camera. If <code>true</code> then the entity is rendered.
|
||||
*
|
||||
* @property {Vec3} position=0,0,0 - The position of the entity.
|
||||
* @property {Quat} rotation=0,0,0,1 - The orientation of the entity with respect to world coordinates.
|
||||
|
@ -595,6 +597,15 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {Entities.RenderInfo} renderInfo - Information on the cost of rendering the entity. Currently information is only
|
||||
* provided for <code>Model</code> entities. <em>Read-only.</em>
|
||||
*
|
||||
* @property {boolean} cloneable=false - If <code>true</code> then the entity can be cloned via {@link Entities.cloneEntity}.
|
||||
* @property {number} cloneLifetime=300 - The entity lifetime for clones created from this entity.
|
||||
* @property {number} cloneLimit=0 - The total number of clones of this entity that can exist in the domain at any given time.
|
||||
* @property {boolean} cloneDynamic=false - If <code>true</code> then clones created from this entity will have their
|
||||
* <code>dynamic</code> property set to <code>true</code>.
|
||||
* @property {boolean} cloneAvatarEntity=false - If <code>true</code> then clones created from this entity will be created as
|
||||
* avatar entities: their <code>clientOnly</code> property will be set to <code>true</code>.
|
||||
* @property {Uuid} cloneOriginID - The ID of the entity that this entity was cloned from.
|
||||
*
|
||||
* @property {string} itemName="" - Certifiable name of the Marketplace item.
|
||||
* @property {string} itemDescription="" - Certifiable description of the Marketplace item.
|
||||
* @property {string} itemCategories="" - Certifiable category of the Marketplace item.
|
||||
|
@ -1226,6 +1237,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera);
|
||||
|
||||
// Certifiable Properties
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_NAME, itemName);
|
||||
|
@ -1565,6 +1577,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingScale, glmVec2, setMaterialMappingScale);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingRot, float, setMaterialMappingRot);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialData, QString, setMaterialData);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(isVisibleInSecondaryCamera, bool, setIsVisibleInSecondaryCamera);
|
||||
|
||||
// Certifiable Properties
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName);
|
||||
|
@ -1944,6 +1957,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
|||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_DATA, MaterialData, materialData, QString);
|
||||
|
||||
ADD_PROPERTY_TO_MAP(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool);
|
||||
|
||||
// Certifiable Properties
|
||||
ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString);
|
||||
|
@ -3041,6 +3056,8 @@ void EntityItemProperties::markAllChanged() {
|
|||
_cloneDynamicChanged = true;
|
||||
_cloneAvatarEntityChanged = true;
|
||||
_cloneOriginIDChanged = true;
|
||||
|
||||
_isVisibleInSecondaryCameraChanged = true;
|
||||
}
|
||||
|
||||
// The minimum bounding box for the entity.
|
||||
|
@ -3319,6 +3336,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (materialDataChanged()) {
|
||||
out += "materialData";
|
||||
}
|
||||
if (isVisibleInSecondaryCameraChanged()) {
|
||||
out += "isVisibleInSecondaryCamera";
|
||||
}
|
||||
|
||||
// Certifiable Properties
|
||||
if (itemNameChanged()) {
|
||||
|
|
|
@ -233,6 +233,8 @@ public:
|
|||
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float, 0);
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_DATA, MaterialData, materialData, QString, "");
|
||||
|
||||
DEFINE_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool, ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA);
|
||||
|
||||
// Certifiable Properties - related to Proof of Purchase certificates
|
||||
DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME);
|
||||
DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION);
|
||||
|
|
|
@ -46,6 +46,7 @@ const quint32 ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION = 0;
|
|||
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
|
||||
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
|
||||
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
|
||||
const bool ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA = true;
|
||||
const bool ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW { true };
|
||||
|
||||
const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString("");
|
||||
|
|
|
@ -249,6 +249,8 @@ enum EntityPropertyList {
|
|||
PROP_MATERIAL_MAPPING_ROT,
|
||||
PROP_MATERIAL_DATA,
|
||||
|
||||
PROP_VISIBLE_IN_SECONDARY_CAMERA, // not sent over the wire, only used locally
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ATTENTION: add new properties to end of list just ABOVE this line
|
||||
PROP_AFTER_LAST_ITEM,
|
||||
|
|
|
@ -225,12 +225,12 @@ public slots:
|
|||
bool collisionless, const glm::vec3& position, const glm::vec3& gravity);
|
||||
|
||||
/**jsdoc
|
||||
* Request a clone of an entity. Only entities that have been marked as 'cloneable' will be able to be cloned using this method.
|
||||
* A cloned entity has most of the properties of the orignal entity, and can be requested from clients that do not have rez permissions.
|
||||
* The client requests a clone from the entity server, which returns back the entityID of a valid clone if the operation was allowed.
|
||||
* Create a clone of an entity. A clone can be created by a client that doesn't have rez permissions in the current domain.
|
||||
* The entity must have its <code>cloneable</code> property set to <code>true</code>. The clone has a modified name, other
|
||||
* properties set per its clone related-properties, and its clone-related properties are set to defaults.
|
||||
* @function Entities.cloneEntity
|
||||
* @param {Uuid} entityIDToClone - the ID of the entity to clone
|
||||
* @returns {Entities.EntityID} The ID of the newly created clone
|
||||
* @param {Uuid} entityID - The ID of the entity to clone.
|
||||
* @returns {Uuid} The ID of the new entity if successfully cloned, otherwise {@link Uuid|Uuid.NULL}.
|
||||
*/
|
||||
Q_INVOKABLE QUuid cloneEntity(QUuid entityIDToClone);
|
||||
|
||||
|
|
|
@ -684,9 +684,9 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
|
||||
PROFILE_RANGE(render_gpu, "sphericalHarmonicsFromTexture");
|
||||
|
||||
#ifndef USE_GLES
|
||||
auto mipFormat = cubeTexture.getStoredMipFormat();
|
||||
std::function<glm::vec3(uint32)> unpackFunc;
|
||||
|
||||
switch (mipFormat.getSemantic()) {
|
||||
case gpu::R11G11B10:
|
||||
unpackFunc = glm::unpackF2x11_1x10;
|
||||
|
@ -698,6 +698,7 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
assert(false);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
const uint sqOrder = order*order;
|
||||
|
||||
|
@ -732,7 +733,11 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
|
||||
PROFILE_RANGE(render_gpu, "ProcessFace");
|
||||
|
||||
#ifndef USE_GLES
|
||||
auto data = reinterpret_cast<const uint32*>( cubeTexture.accessStoredMipFace(0, face)->readData() );
|
||||
#else
|
||||
auto data = cubeTexture.accessStoredMipFace(0, face)->readData();
|
||||
#endif
|
||||
if (data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
@ -816,8 +821,15 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
glm::vec3 color{ 0.0f, 0.0f, 0.0f };
|
||||
for (int i = 0; i < stride; ++i) {
|
||||
for (int j = 0; j < stride; ++j) {
|
||||
#ifndef USE_GLES
|
||||
int k = (int)(x + i - halfStride + (y + j - halfStride) * width);
|
||||
color += unpackFunc(data[k]);
|
||||
#else
|
||||
const int NUM_COMPONENTS_PER_PIXEL = 4;
|
||||
int k = NUM_COMPONENTS_PER_PIXEL * (int)(x + i - halfStride + (y + j - halfStride) * width);
|
||||
// BGRA -> RGBA
|
||||
color += glm::pow(glm::vec3(data[k + 2], data[k + 1], data[k]) / 255.0f, glm::vec3(2.2f));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
|
|||
if (!Texture::evalKTXFormat(mipFormat, texelFormat, header)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// Set Dimensions
|
||||
uint32_t numFaces = 1;
|
||||
switch (texture.getType()) {
|
||||
|
|
|
@ -2,3 +2,4 @@ set(TARGET_NAME image)
|
|||
setup_hifi_library()
|
||||
link_hifi_libraries(shared gpu)
|
||||
target_nvtt()
|
||||
target_etc2comp()
|
||||
|
|
|
@ -31,8 +31,17 @@ using namespace gpu;
|
|||
#define CPU_MIPMAPS 1
|
||||
#include <nvtt/nvtt.h>
|
||||
|
||||
#ifdef USE_GLES
|
||||
#include <Etc.h>
|
||||
#include <EtcFilter.h>
|
||||
#endif
|
||||
|
||||
static const glm::uvec2 SPARSE_PAGE_SIZE(128);
|
||||
#ifdef Q_OS_ANDROID
|
||||
static const glm::uvec2 MAX_TEXTURE_SIZE(2048);
|
||||
#else
|
||||
static const glm::uvec2 MAX_TEXTURE_SIZE(4096);
|
||||
#endif
|
||||
bool DEV_DECIMATE_TEXTURES = false;
|
||||
std::atomic<size_t> DECIMATED_TEXTURE_COUNT{ 0 };
|
||||
std::atomic<size_t> RECTIFIED_TEXTURE_COUNT{ 0 };
|
||||
|
@ -75,7 +84,13 @@ const QStringList getSupportedFormats() {
|
|||
return stringFormats;
|
||||
}
|
||||
|
||||
|
||||
// On GLES, we don't use HDR skyboxes
|
||||
#ifndef USE_GLES
|
||||
QImage::Format QIMAGE_HDR_FORMAT = QImage::Format_RGB30;
|
||||
#else
|
||||
QImage::Format QIMAGE_HDR_FORMAT = QImage::Format_RGB32;
|
||||
#endif
|
||||
|
||||
TextureUsage::TextureLoader TextureUsage::getTextureLoaderForType(Type type, const QVariantMap& options) {
|
||||
switch (type) {
|
||||
|
@ -548,13 +563,15 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic<bo
|
|||
// https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f18-for-consume-parameters-pass-by-x-and-stdmove-the-parameter
|
||||
QImage localCopy = std::move(image);
|
||||
|
||||
if (localCopy.format() != QImage::Format_ARGB32) {
|
||||
if (localCopy.format() != QImage::Format_ARGB32 && localCopy.format() != QIMAGE_HDR_FORMAT) {
|
||||
localCopy = localCopy.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
const int width = localCopy.width(), height = localCopy.height();
|
||||
const void* data = static_cast<const void*>(localCopy.constBits());
|
||||
auto mipFormat = texture->getStoredMipFormat();
|
||||
|
||||
#ifndef USE_GLES
|
||||
const void* data = static_cast<const void*>(localCopy.constBits());
|
||||
nvtt::TextureType textureType = nvtt::TextureType_2D;
|
||||
nvtt::InputFormat inputFormat = nvtt::InputFormat_BGRA_8UB;
|
||||
nvtt::WrapMode wrapMode = nvtt::WrapMode_Mirror;
|
||||
|
@ -584,8 +601,6 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic<bo
|
|||
nvtt::CompressionOptions compressionOptions;
|
||||
compressionOptions.setQuality(nvtt::Quality_Production);
|
||||
|
||||
// TODO: gles: generate ETC mips instead?
|
||||
auto mipFormat = texture->getStoredMipFormat();
|
||||
if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGB) {
|
||||
compressionOptions.setFormat(nvtt::Format_BC1);
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_MASK) {
|
||||
|
@ -669,21 +684,94 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic<bo
|
|||
nvtt::Compressor compressor;
|
||||
compressor.setTaskDispatcher(&dispatcher);
|
||||
compressor.process(inputOptions, compressionOptions, outputOptions);
|
||||
|
||||
#else
|
||||
int numMips = 1 + (int)log2(std::max(width, height));
|
||||
Etc::RawImage *mipMaps = new Etc::RawImage[numMips];
|
||||
Etc::Image::Format etcFormat = Etc::Image::Format::DEFAULT;
|
||||
|
||||
if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_RGB) {
|
||||
etcFormat = Etc::Image::Format::RGB8;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_SRGB) {
|
||||
etcFormat = Etc::Image::Format::SRGB8;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA) {
|
||||
etcFormat = Etc::Image::Format::RGB8A1;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA) {
|
||||
etcFormat = Etc::Image::Format::SRGB8A1;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_RGBA) {
|
||||
etcFormat = Etc::Image::Format::RGBA8;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA) {
|
||||
etcFormat = Etc::Image::Format::SRGBA8;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_EAC_RED) {
|
||||
etcFormat = Etc::Image::Format::R11;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_EAC_RED_SIGNED) {
|
||||
etcFormat = Etc::Image::Format::SIGNED_R11;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_EAC_XY) {
|
||||
etcFormat = Etc::Image::Format::RG11;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_EAC_XY_SIGNED) {
|
||||
etcFormat = Etc::Image::Format::SIGNED_RG11;
|
||||
} else {
|
||||
qCWarning(imagelogging) << "Unknown mip format";
|
||||
Q_UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
const Etc::ErrorMetric errorMetric = Etc::ErrorMetric::RGBA;
|
||||
const float effort = 1.0f;
|
||||
const int numEncodeThreads = 4;
|
||||
int encodingTime;
|
||||
const float MAX_COLOR = 255.0f;
|
||||
|
||||
std::vector<vec4> floatData;
|
||||
floatData.resize(width * height);
|
||||
for (int y = 0; y < height; y++) {
|
||||
QRgb *line = (QRgb *) localCopy.scanLine(y);
|
||||
for (int x = 0; x < width; x++) {
|
||||
QRgb &pixel = line[x];
|
||||
floatData[x + y * width] = vec4(qRed(pixel), qGreen(pixel), qBlue(pixel), qAlpha(pixel)) / MAX_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
// free up the memory afterward to avoid bloating the heap
|
||||
localCopy = QImage(); // QImage doesn't have a clear function, so override it with an empty one.
|
||||
|
||||
Etc::EncodeMipmaps(
|
||||
(float *)floatData.data(), width, height,
|
||||
etcFormat, errorMetric, effort,
|
||||
numEncodeThreads, numEncodeThreads,
|
||||
numMips, Etc::FILTER_WRAP_NONE,
|
||||
mipMaps, &encodingTime
|
||||
);
|
||||
|
||||
for (int i = 0; i < numMips; i++) {
|
||||
if (mipMaps[i].paucEncodingBits.get()) {
|
||||
if (face >= 0) {
|
||||
texture->assignStoredMipFace(i, face, mipMaps[i].uiEncodingBitsBytes, static_cast<const gpu::Byte*>(mipMaps[i].paucEncodingBits.get()));
|
||||
} else {
|
||||
texture->assignStoredMip(i, mipMaps[i].uiEncodingBitsBytes, static_cast<const gpu::Byte*>(mipMaps[i].paucEncodingBits.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] mipMaps;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void generateMips(gpu::Texture* texture, QImage&& image, const std::atomic<bool>& abortProcessing = false, int face = -1) {
|
||||
#if CPU_MIPMAPS
|
||||
PROFILE_RANGE(resource_parse, "generateMips");
|
||||
|
||||
#ifndef USE_GLES
|
||||
if (image.format() == QIMAGE_HDR_FORMAT) {
|
||||
generateHDRMips(texture, std::move(image), abortProcessing, face);
|
||||
} else {
|
||||
generateLDRMips(texture, std::move(image), abortProcessing, face);
|
||||
}
|
||||
#else
|
||||
generateLDRMips(texture, std::move(image), abortProcessing, face);
|
||||
#endif
|
||||
#else
|
||||
texture->setAutoGenerateMips(true);
|
||||
#endif
|
||||
|
@ -738,7 +826,6 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma
|
|||
gpu::Element formatMip;
|
||||
gpu::Element formatGPU;
|
||||
if (isColorTexturesCompressionEnabled()) {
|
||||
#ifndef USE_GLES
|
||||
if (validAlpha) {
|
||||
// NOTE: This disables BC1a compression because it was producing odd artifacts on text textures
|
||||
// for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts).
|
||||
|
@ -746,22 +833,15 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma
|
|||
} else {
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_SRGB;
|
||||
}
|
||||
#else
|
||||
if (validAlpha) {
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA;
|
||||
} else {
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGB;
|
||||
}
|
||||
#endif
|
||||
formatMip = formatGPU;
|
||||
} else {
|
||||
#ifdef USE_GLES
|
||||
// GLES does not support GL_BGRA
|
||||
formatMip = gpu::Element::COLOR_SRGBA_32;
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA;
|
||||
formatMip = formatGPU;
|
||||
#else
|
||||
formatGPU = gpu::Element::COLOR_SRGBA_32;
|
||||
formatMip = gpu::Element::COLOR_SBGRA_32;
|
||||
#endif
|
||||
formatGPU = gpu::Element::COLOR_SRGBA_32;
|
||||
}
|
||||
|
||||
if (isStrict) {
|
||||
|
@ -876,16 +956,18 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr
|
|||
|
||||
gpu::TexturePointer theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
gpu::Element formatMip = gpu::Element::VEC2NU8_XY;
|
||||
gpu::Element formatGPU = gpu::Element::VEC2NU8_XY;
|
||||
gpu::Element formatMip;
|
||||
gpu::Element formatGPU;
|
||||
if (isNormalTexturesCompressionEnabled()) {
|
||||
#ifndef USE_GLES
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_XY;
|
||||
#else
|
||||
} else {
|
||||
#ifdef USE_GLES
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_XY;
|
||||
#else
|
||||
formatGPU = gpu::Element::VEC2NU8_XY;
|
||||
#endif
|
||||
formatMip = formatGPU;
|
||||
}
|
||||
formatMip = formatGPU;
|
||||
|
||||
theTexture = gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
|
||||
theTexture->setSource(srcImageName);
|
||||
|
@ -917,16 +999,15 @@ gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& sr
|
|||
gpu::Element formatMip;
|
||||
gpu::Element formatGPU;
|
||||
if (isGrayscaleTexturesCompressionEnabled()) {
|
||||
#ifndef USE_GLES
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_RED;
|
||||
#else
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED;
|
||||
#endif
|
||||
formatMip = formatGPU;
|
||||
} else {
|
||||
formatMip = gpu::Element::COLOR_R_8;
|
||||
#ifdef USE_GLES
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED;
|
||||
#else
|
||||
formatGPU = gpu::Element::COLOR_R_8;
|
||||
#endif
|
||||
}
|
||||
formatMip = formatGPU;
|
||||
|
||||
theTexture = gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
|
||||
theTexture->setSource(srcImageName);
|
||||
|
@ -1283,19 +1364,25 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI
|
|||
QImage image = processSourceImage(std::move(localCopy), true);
|
||||
|
||||
if (image.format() != QIMAGE_HDR_FORMAT) {
|
||||
#ifndef USE_GLES
|
||||
image = convertToHDRFormat(std::move(image), HDR_FORMAT);
|
||||
#else
|
||||
image = image.convertToFormat(QImage::Format_RGB32);
|
||||
#endif
|
||||
}
|
||||
|
||||
gpu::Element formatMip;
|
||||
gpu::Element formatGPU;
|
||||
if (isCubeTexturesCompressionEnabled()) {
|
||||
// TODO: gles: pick HDR ETC format
|
||||
formatMip = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB;
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB;
|
||||
} else {
|
||||
formatMip = HDR_FORMAT;
|
||||
#ifdef USE_GLES
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGB;
|
||||
#else
|
||||
formatGPU = HDR_FORMAT;
|
||||
#endif
|
||||
}
|
||||
formatMip = formatGPU;
|
||||
|
||||
// Find the layout of the cubemap in the 2D image
|
||||
// Use the original image size since processSourceImage may have altered the size / aspect ratio
|
||||
|
@ -1342,9 +1429,16 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI
|
|||
// Generate irradiance while we are at it
|
||||
if (generateIrradiance) {
|
||||
PROFILE_RANGE(resource_parse, "generateIrradiance");
|
||||
auto irradianceTexture = gpu::Texture::createCube(HDR_FORMAT, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
gpu::Element irradianceFormat;
|
||||
// TODO: we could locally compress the irradiance texture on Android, but we don't need to
|
||||
#ifndef USE_GLES
|
||||
irradianceFormat = HDR_FORMAT;
|
||||
#else
|
||||
irradianceFormat = gpu::Element::COLOR_SRGBA_32;
|
||||
#endif
|
||||
auto irradianceTexture = gpu::Texture::createCube(irradianceFormat, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
irradianceTexture->setSource(srcImageName);
|
||||
irradianceTexture->setStoredMipFormat(HDR_FORMAT);
|
||||
irradianceTexture->setStoredMipFormat(irradianceFormat);
|
||||
for (uint8 face = 0; face < faces.size(); ++face) {
|
||||
irradianceTexture->assignStoredMipFace(0, face, faces[face].byteCount(), faces[face].constBits());
|
||||
}
|
||||
|
|
|
@ -350,6 +350,8 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) {
|
|||
if (idxMoveStartingPointCandidate != -1) {
|
||||
_moveCurrentTouchId = tPoints[idxMoveStartingPointCandidate].id();
|
||||
_unusedTouches.erase(_moveCurrentTouchId);
|
||||
thisPoint.x = tPoints[idxMoveStartingPointCandidate].pos().x();
|
||||
thisPoint.y = tPoints[idxMoveStartingPointCandidate].pos().y();
|
||||
moveTouchBegin(thisPoint);
|
||||
} else {
|
||||
moveTouchEnd();
|
||||
|
@ -359,6 +361,8 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) {
|
|||
if (idxViewStartingPointCandidate != -1) {
|
||||
_viewCurrentTouchId = tPoints[idxViewStartingPointCandidate].id();
|
||||
_unusedTouches.erase(_viewCurrentTouchId);
|
||||
thisPoint.x = tPoints[idxViewStartingPointCandidate].pos().x();
|
||||
thisPoint.y = tPoints[idxViewStartingPointCandidate].pos().y();
|
||||
viewTouchBegin(thisPoint);
|
||||
} else {
|
||||
viewTouchEnd();
|
||||
|
@ -368,6 +372,8 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) {
|
|||
if (idxJumpStartingPointCandidate != -1) {
|
||||
_jumpCurrentTouchId = tPoints[idxJumpStartingPointCandidate].id();
|
||||
_unusedTouches.erase(_jumpCurrentTouchId);
|
||||
thisPoint.x = tPoints[idxJumpStartingPointCandidate].pos().x();
|
||||
thisPoint.y = tPoints[idxJumpStartingPointCandidate].pos().y();
|
||||
jumpTouchBegin(thisPoint);
|
||||
} else {
|
||||
if (_jumpHasValidTouch) {
|
||||
|
@ -424,6 +430,7 @@ void TouchscreenVirtualPadDevice::moveTouchBegin(glm::vec2 touchPoint) {
|
|||
} else {
|
||||
_moveRefTouchPoint = touchPoint;
|
||||
}
|
||||
_moveCurrentTouchPoint = touchPoint;
|
||||
_moveHasValidTouch = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -636,7 +636,10 @@ void Resource::attemptRequest() {
|
|||
<< "- retrying asset load - attempt" << _attempts << " of " << MAX_ATTEMPTS;
|
||||
}
|
||||
|
||||
ResourceCache::attemptRequest(_self);
|
||||
auto self = _self.lock();
|
||||
if (self) {
|
||||
ResourceCache::attemptRequest(self);
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::finishedLoading(bool success) {
|
||||
|
|
|
@ -40,7 +40,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::AvatarData:
|
||||
case PacketType::BulkAvatarData:
|
||||
case PacketType::KillAvatar:
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::FBXReaderNodeReparenting);
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::FixMannequinDefaultAvatarFeet);
|
||||
case PacketType::MessagesData:
|
||||
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
||||
// ICE packets
|
||||
|
|
|
@ -282,7 +282,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
|||
AvatarIdentityLookAtSnapping,
|
||||
UpdatedMannequinDefaultAvatar,
|
||||
AvatarJointDefaultPoseFlags,
|
||||
FBXReaderNodeReparenting
|
||||
FBXReaderNodeReparenting,
|
||||
FixMannequinDefaultAvatarFeet
|
||||
};
|
||||
|
||||
enum class DomainConnectRequestVersion : PacketVersion {
|
||||
|
|
|
@ -40,9 +40,10 @@ bool readOctreeFile(QString path, QJsonDocument* doc) {
|
|||
}
|
||||
|
||||
bool OctreeUtils::RawOctreeData::readOctreeDataInfoFromJSON(QJsonObject root) {
|
||||
if (root.contains("Id") && root.contains("DataVersion")) {
|
||||
if (root.contains("Id") && root.contains("DataVersion") && root.contains("Version")) {
|
||||
id = root["Id"].toVariant().toUuid();
|
||||
version = root["DataVersion"].toInt();
|
||||
dataVersion = root["DataVersion"].toInt();
|
||||
version = root["Version"].toInt();
|
||||
}
|
||||
readSubclassData(root);
|
||||
return true;
|
||||
|
@ -76,11 +77,10 @@ bool OctreeUtils::RawOctreeData::readOctreeDataInfoFromFile(QString path) {
|
|||
}
|
||||
|
||||
QByteArray OctreeUtils::RawOctreeData::toByteArray() {
|
||||
const auto protocolVersion = (int)versionForPacketType((PacketTypeEnum::Value)dataPacketType());
|
||||
QJsonObject obj {
|
||||
{ "DataVersion", QJsonValue((qint64)version) },
|
||||
{ "DataVersion", QJsonValue((qint64)dataVersion) },
|
||||
{ "Id", QJsonValue(id.toString()) },
|
||||
{ "Version", protocolVersion },
|
||||
{ "Version", QJsonValue((qint64)version) },
|
||||
};
|
||||
|
||||
writeSubclassData(obj);
|
||||
|
@ -111,8 +111,8 @@ PacketType OctreeUtils::RawOctreeData::dataPacketType() const {
|
|||
|
||||
void OctreeUtils::RawOctreeData::resetIdAndVersion() {
|
||||
id = QUuid::createUuid();
|
||||
version = OctreeUtils::INITIAL_VERSION;
|
||||
qDebug() << "Reset octree data to: " << id << version;
|
||||
dataVersion = OctreeUtils::INITIAL_VERSION;
|
||||
qDebug() << "Reset octree data to: " << id << dataVersion;
|
||||
}
|
||||
|
||||
void OctreeUtils::RawEntityData::readSubclassData(const QJsonObject& root) {
|
||||
|
|
|
@ -28,6 +28,7 @@ constexpr Version INITIAL_VERSION = 0;
|
|||
class RawOctreeData {
|
||||
public:
|
||||
QUuid id { QUuid() };
|
||||
Version dataVersion { -1 };
|
||||
Version version { -1 };
|
||||
|
||||
virtual PacketType dataPacketType() const;
|
||||
|
|
|
@ -179,8 +179,8 @@ bool OctreePersistThread::process() {
|
|||
|
||||
OctreeUtils::RawOctreeData data;
|
||||
if (data.readOctreeDataInfoFromFile(_filename)) {
|
||||
qDebug() << "Setting entity version info to: " << data.id << data.version;
|
||||
_tree->setOctreeVersionInfo(data.id, data.version);
|
||||
qDebug() << "Setting entity version info to: " << data.id << data.dataVersion;
|
||||
_tree->setOctreeVersionInfo(data.id, data.dataVersion);
|
||||
}
|
||||
|
||||
bool persistentFileRead;
|
||||
|
|
|
@ -446,17 +446,13 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
|||
// this case is prevented by setting _ownershipState to UNOWNABLE in EntityMotionState::ctor
|
||||
assert(!(_entity->getClientOnly() && _entity->getOwningAvatarID() != Physics::getSessionUUID()));
|
||||
|
||||
// shouldSendUpdate() sould NOT be triggering updates to maintain the queryAACube of dynamic entities.
|
||||
// The server is supposed to predict the transform of such moving things. The client performs a "double prediction"
|
||||
// where it predicts what the the server is doing, and only sends updates whent the entity's true transform
|
||||
// differs significantly. That is what the remoteSimulationOutOfSync() logic is all about.
|
||||
if (_entity->dynamicDataNeedsTransmit() ||
|
||||
(!_entity->getDynamic() && _entity->queryAACubeNeedsUpdate())) {
|
||||
if (_entity->dynamicDataNeedsTransmit()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_entity->shouldSuppressLocationEdits()) {
|
||||
return false;
|
||||
// "shouldSuppressLocationEdits" really means: "the entity has a 'Hold' action therefore
|
||||
// we don't need send an update unless the entity is not contained by its queryAACube"
|
||||
return _entity->queryAACubeNeedsUpdate();
|
||||
}
|
||||
|
||||
return remoteSimulationOutOfSync(simulationStep);
|
||||
|
|
|
@ -87,7 +87,8 @@ void CauterizedModel::createVisibleRenderItemSet() {
|
|||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
||||
_modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr);
|
||||
_modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName());
|
||||
auto material = getGeometry()->getShapeMaterial(shapeID);
|
||||
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
|
||||
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
|
||||
shapeID++;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,9 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render:
|
|||
|
||||
// Warning : the cull functor passed to the shadow pass should only be testing for LOD culling. If frustum culling
|
||||
// is performed, then casters not in the view frustum will be removed, which is not what we wish.
|
||||
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor, tagBits, tagMask);
|
||||
if (isDeferred) {
|
||||
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor, tagBits, tagMask);
|
||||
}
|
||||
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, tagBits, tagMask);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue