Merge branch 'master' into M17217-b

This commit is contained in:
David Rowe 2018-08-21 11:25:58 +12:00
commit 0a82f8adc9
170 changed files with 1479 additions and 525 deletions

View file

@ -145,5 +145,7 @@ dependencies {
compile 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.picasso:picasso:2.71828'
compile 'com.sothree.slidinguppanel:library:3.4.0'
implementation fileTree(include: ['*.jar'], dir: 'libs')
}

View file

@ -209,6 +209,11 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGotoUr
DependencyManager::get<AddressManager>()->loadSettings(jniUrl.toString());
}
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGoToUser(JNIEnv* env, jobject obj, jstring username) {
QAndroidJniObject jniUsername("java/lang/String", "(Ljava/lang/String;)V", username);
DependencyManager::get<AddressManager>()->goToUser(jniUsername.toString(), false);
}
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnPause(JNIEnv* env, jobject obj) {
}
@ -285,6 +290,18 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *en
Q_ARG(const QString&, username), Q_ARG(const QString&, password));
}
JNIEXPORT jboolean JNICALL
Java_io_highfidelity_hifiinterface_fragment_FriendsFragment_nativeIsLoggedIn(JNIEnv *env, jobject instance) {
auto accountManager = DependencyManager::get<AccountManager>();
return accountManager->isLoggedIn();
}
JNIEXPORT jstring JNICALL
Java_io_highfidelity_hifiinterface_fragment_FriendsFragment_nativeGetAccessToken(JNIEnv *env, jobject instance) {
auto accountManager = DependencyManager::get<AccountManager>();
return env->NewStringUTF(accountManager->getAccountInfo().getAccessToken().token.toLatin1().data());
}
JNIEXPORT void JNICALL
Java_io_highfidelity_hifiinterface_SplashActivity_registerLoadCompleteListener(JNIEnv *env,
jobject instance) {

View file

@ -48,6 +48,7 @@ import com.google.vr.ndk.base.GvrApi;*/
public class InterfaceActivity extends QtActivity implements WebViewFragment.OnWebViewInteractionListener {
public static final String DOMAIN_URL = "url";
public static final String EXTRA_GOTO_USERNAME = "gotousername";
private static final String TAG = "Interface";
private static final int WEB_DRAWER_RIGHT_MARGIN = 262;
private static final int WEB_DRAWER_BOTTOM_MARGIN = 150;
@ -59,6 +60,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
private native long nativeOnCreate(InterfaceActivity instance, AssetManager assetManager);
private native void nativeOnDestroy();
private native void nativeGotoUrl(String url);
private native void nativeGoToUser(String username);
private native void nativeBeforeEnterBackground();
private native void nativeEnterBackground();
private native void nativeEnterForeground();
@ -280,6 +282,9 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
if (intent.hasExtra(DOMAIN_URL)) {
webSlidingDrawer.setVisibility(View.GONE);
nativeGotoUrl(intent.getStringExtra(DOMAIN_URL));
} else if (intent.hasExtra(EXTRA_GOTO_USERNAME)) {
webSlidingDrawer.setVisibility(View.GONE);
nativeGoToUser(intent.getStringExtra(EXTRA_GOTO_USERNAME));
}
}

View file

@ -29,6 +29,7 @@ import android.widget.TextView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import io.highfidelity.hifiinterface.fragment.FriendsFragment;
import io.highfidelity.hifiinterface.fragment.HomeFragment;
import io.highfidelity.hifiinterface.fragment.LoginFragment;
import io.highfidelity.hifiinterface.fragment.PolicyFragment;
@ -36,7 +37,8 @@ import io.highfidelity.hifiinterface.task.DownloadProfileImageTask;
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener,
LoginFragment.OnLoginInteractionListener,
HomeFragment.OnHomeInteractionListener {
HomeFragment.OnHomeInteractionListener,
FriendsFragment.OnHomeInteractionListener {
private static final int PROFILE_PICTURE_PLACEHOLDER = R.drawable.default_profile_avatar;
public static final String DEFAULT_FRAGMENT = "Home";
@ -56,6 +58,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
private View mLoginPanel;
private View mProfilePanel;
private TextView mLogoutOption;
private MenuItem mPeopleMenuItem;
private boolean backToScene;
@ -75,6 +78,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
mDisplayName = mNavigationView.getHeaderView(0).findViewById(R.id.displayName);
mProfilePicture = mNavigationView.getHeaderView(0).findViewById(R.id.profilePicture);
mPeopleMenuItem = mNavigationView.getMenu().findItem(R.id.action_people);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitleTextAppearance(this, R.style.HomeActionBarTitleStyle);
setSupportActionBar(toolbar);
@ -109,40 +114,69 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
loadLoginFragment();
break;
case "Home":
loadHomeFragment();
loadHomeFragment(true);
break;
case "Privacy Policy":
loadPrivacyPolicyFragment();
break;
case "People":
loadPeopleFragment();
break;
default:
Log.e(TAG, "Unknown fragment " + fragment);
}
}
private void loadHomeFragment() {
private void loadHomeFragment(boolean addToBackStack) {
Fragment fragment = HomeFragment.newInstance();
loadFragment(fragment, getString(R.string.home), false);
loadFragment(fragment, getString(R.string.home), getString(R.string.tagFragmentHome), addToBackStack);
}
private void loadLoginFragment() {
Fragment fragment = LoginFragment.newInstance();
loadFragment(fragment, getString(R.string.login), true);
loadFragment(fragment, getString(R.string.login), getString(R.string.tagFragmentLogin), true);
}
private void loadPrivacyPolicyFragment() {
Fragment fragment = PolicyFragment.newInstance();
loadFragment(fragment, getString(R.string.privacyPolicy), true);
loadFragment(fragment, getString(R.string.privacyPolicy), getString(R.string.tagFragmentPolicy), true);
}
private void loadFragment(Fragment fragment, String title, boolean addToBackStack) {
private void loadPeopleFragment() {
Fragment fragment = FriendsFragment.newInstance();
loadFragment(fragment, getString(R.string.people), getString(R.string.tagFragmentPeople), true);
}
private void loadFragment(Fragment fragment, String title, String tag, boolean addToBackStack) {
FragmentManager fragmentManager = getFragmentManager();
// check if it's the same fragment
String currentFragmentName = fragmentManager.getBackStackEntryCount() > 0
? fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName()
: "";
if (currentFragmentName.equals(title)) {
mDrawerLayout.closeDrawer(mNavigationView);
return; // cancel as we are already in that fragment
}
// go back until first transaction
int backStackEntryCount = fragmentManager.getBackStackEntryCount();
for (int i = 0; i < backStackEntryCount - 1; i++) {
fragmentManager.popBackStackImmediate();
}
// this case is when we wanted to go home.. rollback already did that!
// But asking for a new Home fragment makes it easier to have an updated list so we let it to continue
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.replace(R.id.content_frame, fragment, tag);
if (addToBackStack) {
ft.addToBackStack(null);
ft.addToBackStack(title);
}
ft.commit();
setTitle(title);
@ -155,11 +189,13 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
mLoginPanel.setVisibility(View.GONE);
mProfilePanel.setVisibility(View.VISIBLE);
mLogoutOption.setVisibility(View.VISIBLE);
mPeopleMenuItem.setVisible(true);
updateProfileHeader();
} else {
mLoginPanel.setVisibility(View.VISIBLE);
mProfilePanel.setVisibility(View.GONE);
mLogoutOption.setVisibility(View.GONE);
mPeopleMenuItem.setVisible(false);
mDisplayName.setText("");
}
}
@ -200,7 +236,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch(item.getItemId()) {
case R.id.action_home:
loadHomeFragment();
loadHomeFragment(false);
return true;
case R.id.action_people:
loadPeopleFragment();
return true;
}
return false;
@ -219,6 +258,19 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
public void onLogoutClicked(View view) {
nativeLogout();
updateLoginMenu();
exitLoggedInFragment();
}
private void exitLoggedInFragment() {
// If we are in a "logged in" fragment (like People), go back to home. This could be expanded to multiple fragments
FragmentManager fragmentManager = getFragmentManager();
String currentFragmentName = fragmentManager.getBackStackEntryCount() > 0
? fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName()
: "";
if (currentFragmentName.equals(getString(R.string.people))) {
loadHomeFragment(false);
}
}
public void onSelectedDomain(String domainUrl) {
@ -237,9 +289,17 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
startActivity(intent);
}
private void goToUser(String username) {
Intent intent = new Intent(this, InterfaceActivity.class);
intent.putExtra(InterfaceActivity.EXTRA_GOTO_USERNAME, username);
finish();
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
@Override
public void onLoginCompleted() {
loadHomeFragment();
loadHomeFragment(false);
updateLoginMenu();
if (backToScene) {
backToScene = false;
@ -266,6 +326,11 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
loadPrivacyPolicyFragment();
}
@Override
public void onVisitUserSelected(String username) {
goToUser(username);
}
private class RoundProfilePictureCallback implements Callback {
@Override
public void onSuccess() {
@ -284,15 +349,30 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
@Override
public void onBackPressed() {
int index = getFragmentManager().getBackStackEntryCount() - 1;
if (index > -1) {
// if a fragment needs to internally manage back presses..
FragmentManager fm = getFragmentManager();
Log.d("[BACK]", "getBackStackEntryCount " + fm.getBackStackEntryCount());
Fragment friendsFragment = fm.findFragmentByTag(getString(R.string.tagFragmentPeople));
if (friendsFragment != null && friendsFragment instanceof FriendsFragment) {
if (((FriendsFragment) friendsFragment).onBackPressed()) {
return;
}
}
int index = fm.getBackStackEntryCount() - 1;
if (index > 0) {
super.onBackPressed();
index--;
if (index > -1) {
setTitle(fm.getBackStackEntryAt(index).getName());
}
if (backToScene) {
backToScene = false;
goToLastLocation();
}
} else {
finishAffinity();
finishAffinity();
}
}

View file

@ -0,0 +1,193 @@
package io.highfidelity.hifiinterface.fragment;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
import io.highfidelity.hifiinterface.R;
import io.highfidelity.hifiinterface.provider.EndpointUsersProvider;
import io.highfidelity.hifiinterface.provider.UsersProvider;
import io.highfidelity.hifiinterface.view.UserListAdapter;
public class FriendsFragment extends Fragment {
public native boolean nativeIsLoggedIn();
public native String nativeGetAccessToken();
private RecyclerView mUsersView;
private View mUserActions;
private UserListAdapter mUsersAdapter;
private SlidingUpPanelLayout mSlidingUpPanelLayout;
private EndpointUsersProvider mUsersProvider;
private String mSelectedUsername;
private OnHomeInteractionListener mListener;
private SwipeRefreshLayout mSwipeRefreshLayout;
public FriendsFragment() {
// Required empty public constructor
}
public static FriendsFragment newInstance() {
FriendsFragment fragment = new FriendsFragment();
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_friends, container, false);
String accessToken = nativeGetAccessToken();
mUsersProvider = new EndpointUsersProvider(accessToken);
Log.d("[USERS]", "token : [" + accessToken + "]");
mSwipeRefreshLayout = rootView.findViewById(R.id.swipeRefreshLayout);
mUsersView = rootView.findViewById(R.id.rvUsers);
int numberOfColumns = 1;
GridLayoutManager gridLayoutMgr = new GridLayoutManager(getContext(), numberOfColumns);
mUsersView.setLayoutManager(gridLayoutMgr);
mUsersAdapter = new UserListAdapter(getContext(), mUsersProvider);
mSwipeRefreshLayout.setRefreshing(true);
mUserActions = rootView.findViewById(R.id.userActionsLayout);
mSlidingUpPanelLayout = rootView.findViewById(R.id.sliding_layout);
mSlidingUpPanelLayout.setPanelHeight(0);
rootView.findViewById(R.id.userActionDelete).setOnClickListener(view -> onRemoveConnectionClick());
rootView.findViewById(R.id.userActionVisit).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mListener != null && mSelectedUsername != null) {
mListener.onVisitUserSelected(mSelectedUsername);
}
}
});
mUsersAdapter.setClickListener(new UserListAdapter.ItemClickListener() {
@Override
public void onItemClick(View view, int position, UserListAdapter.User user) {
// 1. 'select' user
mSelectedUsername = user.name;
// ..
// 2. adapt options
// ..
rootView.findViewById(R.id.userActionVisit).setVisibility(user.online ? View.VISIBLE : View.GONE);
// 3. show
mSlidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED);
}
});
mUsersAdapter.setListener(new UserListAdapter.AdapterListener() {
@Override
public void onEmptyAdapter() {
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void onNonEmptyAdapter() {
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void onError(Exception e, String message) {
mSwipeRefreshLayout.setRefreshing(false);
}
});
mUsersView.setAdapter(mUsersAdapter);
mSlidingUpPanelLayout.setFadeOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mSlidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
mSelectedUsername = null;
}
});
mSwipeRefreshLayout.setOnRefreshListener(() -> mUsersAdapter.loadUsers());
return rootView;
}
private void onRemoveConnectionClick() {
if (mSelectedUsername == null) {
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Remove '" + mSelectedUsername + "' from People?");
builder.setPositiveButton("Remove", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
mUsersProvider.removeConnection(mSelectedUsername, new UsersProvider.UserActionCallback() {
@Override
public void requestOk() {
mSlidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
mSelectedUsername = null;
mUsersAdapter.loadUsers();
}
@Override
public void requestError(Exception e, String message) {
// CLD: Show error message?
}
});
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// Cancelled, nothing to do
}
});
builder.show();
}
/**
* Processes the back pressed event and returns true if it was managed by this Fragment
* @return
*/
public boolean onBackPressed() {
if (mSlidingUpPanelLayout.getPanelState().equals(SlidingUpPanelLayout.PanelState.EXPANDED)) {
mSlidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
mSelectedUsername = null;
return true;
} else {
return false;
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnHomeInteractionListener) {
mListener = (OnHomeInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnHomeInteractionListener");
}
}
public interface OnHomeInteractionListener {
void onVisitUserSelected(String username);
}
}

View file

@ -0,0 +1,225 @@
package io.highfidelity.hifiinterface.provider;
import android.util.Log;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import io.highfidelity.hifiinterface.view.UserListAdapter;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;
/**
* Created by cduarte on 6/13/18.
*/
public class EndpointUsersProvider implements UsersProvider {
public static final String BASE_URL = "https://metaverse.highfidelity.com/";
private final Retrofit mRetrofit;
private final EndpointUsersProviderService mEndpointUsersProviderService;
public EndpointUsersProvider(String accessToken) {
mRetrofit = createAuthorizedRetrofit(accessToken);
mEndpointUsersProviderService = mRetrofit.create(EndpointUsersProviderService.class);
}
private Retrofit createAuthorizedRetrofit(String accessToken) {
Retrofit mRetrofit;
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", "Bearer " + accessToken)
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
mRetrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return mRetrofit;
}
@Override
public void retrieve(UsersCallback usersCallback) {
Call<UsersResponse> friendsCall = mEndpointUsersProviderService.getUsers(
CONNECTION_FILTER_CONNECTIONS,
400,
null);
friendsCall.enqueue(new Callback<UsersResponse>() {
@Override
public void onResponse(Call<UsersResponse> call, retrofit2.Response<UsersResponse> response) {
if (!response.isSuccessful()) {
usersCallback.retrieveError(new Exception("Error calling Users API"), "Error calling Users API");
return;
}
UsersResponse usersResponse = response.body();
List<UserListAdapter.User> adapterUsers = new ArrayList<>(usersResponse.total_entries);
for (User user : usersResponse.data.users) {
UserListAdapter.User adapterUser = new UserListAdapter.User();
adapterUser.connection = user.connection;
adapterUser.imageUrl = user.images.thumbnail;
adapterUser.name = user.username;
adapterUser.online = user.online;
adapterUser.locationName = (user.location != null ?
(user.location.root != null ? user.location.root.name :
(user.location.domain != null ? user.location.domain.name : ""))
: "");
adapterUsers.add(adapterUser);
}
usersCallback.retrieveOk(adapterUsers);
}
@Override
public void onFailure(Call<UsersResponse> call, Throwable t) {
usersCallback.retrieveError(new Exception(t), "Error calling Users API");
}
});
}
public class UserActionRetrofitCallback implements Callback<UsersResponse> {
UserActionCallback callback;
public UserActionRetrofitCallback(UserActionCallback callback) {
this.callback = callback;
}
@Override
public void onResponse(Call<UsersResponse> call, retrofit2.Response<UsersResponse> response) {
if (!response.isSuccessful()) {
callback.requestError(new Exception("Error with "
+ call.request().url().toString() + " "
+ call.request().method() + " call " + response.message()),
response.message());
return;
}
if (response.body() == null || !"success".equals(response.body().status)) {
callback.requestError(new Exception("Error with "
+ call.request().url().toString() + " "
+ call.request().method() + " call " + response.message()),
response.message());
return;
}
callback.requestOk();
}
@Override
public void onFailure(Call<UsersResponse> call, Throwable t) {
callback.requestError(new Exception(t), t.getMessage());
}
}
@Override
public void addFriend(String friendUserName, UserActionCallback callback) {
Call<UsersResponse> friendCall = mEndpointUsersProviderService.addFriend(new BodyAddFriend(friendUserName));
friendCall.enqueue(new UserActionRetrofitCallback(callback));
}
@Override
public void removeFriend(String friendUserName, UserActionCallback callback) {
Call<UsersResponse> friendCall = mEndpointUsersProviderService.removeFriend(friendUserName);
friendCall.enqueue(new UserActionRetrofitCallback(callback));
}
@Override
public void removeConnection(String connectionUserName, UserActionCallback callback) {
Call<UsersResponse> connectionCall = mEndpointUsersProviderService.removeConnection(connectionUserName);
connectionCall.enqueue(new UserActionRetrofitCallback(callback));
}
public interface EndpointUsersProviderService {
@GET("api/v1/users")
Call<UsersResponse> getUsers(@Query("filter") String filter,
@Query("per_page") int perPage,
@Query("online") Boolean online);
@DELETE("api/v1/user/connections/{connectionUserName}")
Call<UsersResponse> removeConnection(@Path("connectionUserName") String connectionUserName);
@DELETE("api/v1/user/friends/{friendUserName}")
Call<UsersResponse> removeFriend(@Path("friendUserName") String friendUserName);
@POST("api/v1/user/friends")
Call<UsersResponse> addFriend(@Body BodyAddFriend friendUserName);
/* response
{
"status": "success"
}
*/
}
class BodyAddFriend {
String username;
public BodyAddFriend(String username) {
this.username = username;
}
}
class UsersResponse {
public UsersResponse() {}
String status;
int current_page;
int total_pages;
int per_page;
int total_entries;
Data data;
}
class Data {
public Data() {}
List<User> users;
}
class User {
public User() {}
String username;
boolean online;
String connection;
Images images;
LocationData location;
}
class Images {
public Images() {}
String hero;
String thumbnail;
String tiny;
}
class LocationData {
public LocationData() {}
NameContainer root;
NameContainer domain;
}
class NameContainer {
String name;
}
}

View file

@ -0,0 +1,35 @@
package io.highfidelity.hifiinterface.provider;
import java.util.List;
import io.highfidelity.hifiinterface.view.UserListAdapter;
/**
* Created by cduarte on 6/13/18.
*/
public interface UsersProvider {
public static String CONNECTION_TYPE_FRIEND = "friend";
public static String CONNECTION_FILTER_CONNECTIONS = "connections";
void retrieve(UsersProvider.UsersCallback usersCallback);
interface UsersCallback {
void retrieveOk(List<UserListAdapter.User> users);
void retrieveError(Exception e, String message);
}
void addFriend(String friendUserName, UserActionCallback callback);
void removeFriend(String friendUserName, UserActionCallback callback);
void removeConnection(String connectionUserName, UserActionCallback callback);
interface UserActionCallback {
void requestOk();
void requestError(Exception e, String message);
}
}

View file

@ -0,0 +1,247 @@
package io.highfidelity.hifiinterface.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.List;
import io.highfidelity.hifiinterface.R;
import io.highfidelity.hifiinterface.provider.UsersProvider;
/**
* Created by cduarte on 6/13/18.
*/
public class UserListAdapter extends RecyclerView.Adapter<UserListAdapter.ViewHolder> {
private UsersProvider mProvider;
private LayoutInflater mInflater;
private Context mContext;
private List<User> mUsers = new ArrayList<>();
private ItemClickListener mClickListener;
private AdapterListener mAdapterListener;
public UserListAdapter(Context c, UsersProvider usersProvider) {
mContext = c;
mInflater = LayoutInflater.from(mContext);
mProvider = usersProvider;
loadUsers();
}
public void setListener(AdapterListener adapterListener) {
mAdapterListener = adapterListener;
}
public void loadUsers() {
mProvider.retrieve(new UsersProvider.UsersCallback() {
@Override
public void retrieveOk(List<User> users) {
mUsers = new ArrayList<>(users);
notifyDataSetChanged();
if (mAdapterListener != null) {
if (mUsers.isEmpty()) {
mAdapterListener.onEmptyAdapter();
} else {
mAdapterListener.onNonEmptyAdapter();
}
}
}
@Override
public void retrieveError(Exception e, String message) {
Log.e("[USERS]", message, e);
if (mAdapterListener != null) {
mAdapterListener.onError(e, message);
}
}
});
}
@Override
public UserListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.user_item, parent, false);
return new UserListAdapter.ViewHolder(view);
}
@Override
public void onBindViewHolder(UserListAdapter.ViewHolder holder, int position) {
User aUser = mUsers.get(position);
holder.mUsername.setText(aUser.name);
holder.mOnlineInfo.setVisibility(aUser.online? View.VISIBLE : View.GONE);
holder.mLocation.setText("- " + aUser.locationName); // Bring info from the API and use it here
holder.mFriendStar.onBindSet(aUser.name, aUser.connection.equals(UsersProvider.CONNECTION_TYPE_FRIEND));
Uri uri = Uri.parse(aUser.imageUrl);
Picasso.get().load(uri).into(holder.mImage, new RoundProfilePictureCallback(holder.mImage));
}
private class RoundProfilePictureCallback implements Callback {
private ImageView mProfilePicture;
public RoundProfilePictureCallback(ImageView imageView) {
mProfilePicture = imageView;
}
@Override
public void onSuccess() {
Bitmap imageBitmap = ((BitmapDrawable) mProfilePicture.getDrawable()).getBitmap();
RoundedBitmapDrawable imageDrawable = RoundedBitmapDrawableFactory.create(mProfilePicture.getContext().getResources(), imageBitmap);
imageDrawable.setCircular(true);
imageDrawable.setCornerRadius(Math.max(imageBitmap.getWidth(), imageBitmap.getHeight()) / 2.0f);
mProfilePicture.setImageDrawable(imageDrawable);
}
@Override
public void onError(Exception e) {
mProfilePicture.setImageResource(R.drawable.default_profile_avatar);
}
}
@Override
public int getItemCount() {
return mUsers.size();
}
public class ToggleWrapper {
private ViewGroup mFrame;
private ImageView mImage;
private boolean mChecked = false;
private String mUsername;
private boolean waitingChangeConfirm = false;
public ToggleWrapper(ViewGroup toggleFrame) {
mFrame = toggleFrame;
mImage = toggleFrame.findViewById(R.id.userFavImage);
mFrame.setOnClickListener(view -> toggle());
}
private void refreshUI() {
mImage.setColorFilter(ContextCompat.getColor(mImage.getContext(),
mChecked ? R.color.starSelectedTint : R.color.starUnselectedTint));
}
class RollbackUICallback implements UsersProvider.UserActionCallback {
boolean previousStatus;
RollbackUICallback(boolean previousStatus) {
this.previousStatus = previousStatus;
}
@Override
public void requestOk() {
if (!waitingChangeConfirm) {
return;
}
mFrame.setClickable(true);
// nothing to do, new status was set
}
@Override
public void requestError(Exception e, String message) {
if (!waitingChangeConfirm) {
return;
}
// new status was not set, rolling back
mChecked = previousStatus;
mFrame.setClickable(true);
refreshUI();
}
}
protected void toggle() {
// TODO API CALL TO CHANGE
final boolean previousStatus = mChecked;
mChecked = !mChecked;
mFrame.setClickable(false);
refreshUI();
waitingChangeConfirm = true;
if (mChecked) {
mProvider.addFriend(mUsername, new RollbackUICallback(previousStatus));
} else {
mProvider.removeFriend(mUsername, new RollbackUICallback(previousStatus));
}
}
protected void onBindSet(String username, boolean checked) {
mChecked = checked;
mUsername = username;
waitingChangeConfirm = false;
mFrame.setClickable(true);
refreshUI();
}
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView mUsername;
TextView mOnline;
View mOnlineInfo;
TextView mLocation;
ImageView mImage;
ToggleWrapper mFriendStar;
public ViewHolder(View itemView) {
super(itemView);
mUsername = itemView.findViewById(R.id.userName);
mOnline = itemView.findViewById(R.id.userOnline);
mImage = itemView.findViewById(R.id.userImage);
mOnlineInfo = itemView.findViewById(R.id.userOnlineInfo);
mLocation = itemView.findViewById(R.id.userLocation);
mFriendStar = new ToggleWrapper(itemView.findViewById(R.id.userFav));
itemView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
int position = getAdapterPosition();
if (mClickListener != null) {
mClickListener.onItemClick(view, position, mUsers.get(position));
}
}
}
// allows clicks events to be caught
public void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
public interface ItemClickListener {
void onItemClick(View view, int position, User user);
}
public static class User {
public String name;
public String imageUrl;
public String connection;
public boolean online;
public String locationName;
public User() {}
}
public interface AdapterListener {
void onEmptyAdapter();
void onNonEmptyAdapter();
void onError(Exception e, String message);
}
}

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>

View file

@ -0,0 +1,4 @@
<vector android:height="31dp" android:viewportHeight="25.0"
android:viewportWidth="27.0" android:width="31dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FBD92A" android:pathData="M12.549,0.927C12.848,0.006 14.152,0.006 14.451,0.927L16.756,8.019C16.889,8.431 17.273,8.71 17.706,8.71H25.164C26.132,8.71 26.535,9.95 25.751,10.519L19.719,14.903C19.368,15.157 19.221,15.608 19.355,16.021L21.66,23.113C21.959,24.034 20.904,24.8 20.121,24.231L14.088,19.847C13.737,19.593 13.263,19.593 12.912,19.847L6.879,24.231C6.096,24.8 5.041,24.034 5.34,23.113L7.645,16.021C7.779,15.608 7.632,15.157 7.282,14.903L1.249,10.519C0.465,9.95 0.868,8.71 1.836,8.71H9.293C9.727,8.71 10.111,8.431 10.245,8.019L12.549,0.927Z"/>
</vector>

View file

@ -0,0 +1,31 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M0.6,3h22.8v18.7h-22.8z"
android:fillAlpha="0"/>
<path
android:fillColor="#FF000000"
android:pathData="M0.6,3h16.3v18.7h-16.3z"
android:fillAlpha="0"/>
<path
android:fillColor="#FF000000"
android:pathData="M0.6,3h16.3v18.7h-16.3z"
android:fillAlpha="0"/>
<path
android:fillColor="#FF000000"
android:pathData="M13.8,9.9h9.6v7.8h-9.6z"
android:fillAlpha="0"/>
<path
android:pathData="M11.9,16.9c-0.2,-0.9 -0.3,-2.3 -0.4,-3.4c-0.1,-0.7 -0.1,-1.3 -0.2,-1.7c0,-0.1 -0.1,-0.3 0.3,-0.4c0.1,0 0.1,0 0.2,-0.1l4.4,-1.7c0.3,-0.1 0.5,-0.4 0.6,-0.7c0.1,-0.3 0.1,-0.7 -0.2,-0.9L16.6,8c-0.2,-0.2 -0.5,-0.3 -0.8,-0.3c-0.1,0 -4.8,0.7 -6.8,0.7c-0.1,0 -0.1,0 -0.1,0c-2,0 -6.9,-0.8 -7,-0.8c-0.4,-0.1 -0.8,0.1 -1,0.4L0.7,8.3C0.6,8.5 0.6,8.8 0.6,9.1c0.1,0.3 0.3,0.5 0.5,0.6C2,10 5,11.2 5.9,11.3c0.2,0 0.4,0.1 0.5,0.6c0.1,0.6 -0.2,3.6 -0.6,5c-0.4,1.4 -1,3.2 -1,3.2c-0.2,0.5 0.1,1 0.6,1.2l0.6,0.2c0.2,0.1 0.5,0.1 0.7,-0.1c0.2,-0.1 0.4,-0.3 0.5,-0.6l1.7,-5l1.6,5.1c0.1,0.3 0.3,0.5 0.5,0.6c0.1,0.1 0.3,0.1 0.4,0.1c0.1,0 0.2,0 0.3,-0.1l0.5,-0.2c0.4,-0.2 0.7,-0.6 0.6,-1.1C12.8,20.3 12.3,18.5 11.9,16.9z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M8.9,7.5c1.3,0 2.3,-1 2.3,-2.3S10.2,3 8.9,3S6.6,4 6.6,5.3S7.7,7.5 8.9,7.5z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M23,13.4L22.6,13c0,0 0,0 0,0l-2.9,-2.8c-0.2,-0.2 -0.5,-0.2 -0.7,0l-0.7,0.7c-0.2,0.2 -0.2,0.5 0,0.7l1.2,1.2h-5.2c-0.3,0 -0.5,0.2 -0.5,0.5v0.9c0,0.3 0.2,0.5 0.5,0.5h5.1l-1.2,1.1c-0.2,0.2 -0.2,0.5 0,0.7l0.7,0.7c0.2,0.2 0.5,0.2 0.7,0l3.3,-3.2C23.2,13.9 23.2,13.6 23,13.4z"
android:fillColor="#FFFFFF"/>
</vector>

View file

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<com.sothree.slidinguppanel.SlidingUpPanelLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
app:umanoFadeColor="@color/slidingUpPanelFadeColor"
app:umanoShadowHeight="4dp"
android:background="@color/backgroundLight">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rvUsers"
android:paddingTop="@dimen/list_vertical_padding"
android:paddingBottom="@dimen/list_vertical_padding"
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
<LinearLayout
android:id="@+id/userActionsLayout"
android:layout_width="match_parent"
android:layout_height="270dp"
android:orientation="vertical"
android:background="@color/backgroundDark">
<android.support.constraint.ConstraintLayout
android:id="@+id/userActionVisit"
android:layout_width="match_parent"
android:layout_height="56dp"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackground">
<ImageView android:id="@+id/userActionVisitIcon"
android:layout_width="16dp"
android:layout_height="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:src="@drawable/ic_teleporticon"
android:tint="@color/white_opaque" />
<TextView android:id="@+id/userActionVisitText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Visit In-World"
android:fontFamily="@font/raleway"
android:textColor="@color/white_opaque"
app:layout_constraintStart_toEndOf="@id/userActionVisitIcon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="32dp" />
</android.support.constraint.ConstraintLayout>
<android.support.constraint.ConstraintLayout
android:id="@+id/userActionDelete"
android:layout_width="match_parent"
android:layout_height="56dp"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackground">
<ImageView android:id="@+id/userActionDeleteIcon"
android:layout_width="16dp"
android:layout_height="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:src="@drawable/ic_delete_black_24dp"
android:tint="@color/white_opaque" />
<TextView android:id="@+id/userActionDeleteText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Remove from People"
android:fontFamily="@font/raleway"
android:textColor="@color/white_opaque"
app:layout_constraintStart_toEndOf="@id/userActionDeleteIcon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="32dp" />
</android.support.constraint.ConstraintLayout>
</LinearLayout>
</com.sothree.slidinguppanel.SlidingUpPanelLayout>

View file

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?attr/selectableItemBackground"
android:clickable="true">
<ImageView
android:id="@+id/userImage"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="@dimen/activity_horizontal_margin"
app:layout_constraintStart_toStartOf="parent"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="@dimen/activity_horizontal_margin"
app:layout_constraintStart_toEndOf="@id/userImage"
android:orientation="vertical">
<TextView
android:id="@+id/userName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/raleway"
android:textColor="@color/menuOption"/>
<LinearLayout android:id="@+id/userOnlineInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/userOnline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/online"
android:fontFamily="@font/raleway"
android:textColor="@color/hifiAquamarine" />
<TextView
android:id="@+id/userLocation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:fontFamily="@font/raleway_italic"
android:textColor="@color/menuOption"/>
</LinearLayout>
</LinearLayout>
<RelativeLayout android:id="@+id/userFav"
android:layout_width="48dp"
android:layout_height="48dp"
android:clickable="true"
android:focusable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginEnd="5.5dp">
<ImageView android:id="@+id/userFavImage"
android:layout_width="27dp"
android:layout_height="27dp"
android:src="@drawable/ic_star"
android:tint="@color/starUnselectedTint"
android:background="?attr/selectableItemBackgroundBorderless"
android:layout_centerInParent="true"
android:layout_marginEnd="0dp" />
</RelativeLayout>
</android.support.constraint.ConstraintLayout>

View file

@ -5,4 +5,8 @@
android:id="@+id/action_home"
android:title="@string/home"
/>
<item
android:id="@+id/action_people"
android:title="@string/people"
/>
</menu>

View file

@ -18,4 +18,8 @@
<color name="black_060">#99000000</color>
<color name="statusbar_color">#292929</color>
<color name="hifiLogoColor">#23B2E7</color>
<color name="hifiAquamarine">#62D5C6</color>
<color name="starSelectedTint">#FBD92A</color>
<color name="starUnselectedTint">#8A8A8A</color>
<color name="slidingUpPanelFadeColor">#40000000</color>
</resources>

View file

@ -37,4 +37,6 @@
<dimen name="header_hifi_height">101dp</dimen>
<dimen name="header_hifi_width">425dp</dimen>
<dimen name="list_vertical_padding">8dp</dimen>
</resources>

View file

@ -1,6 +1,7 @@
<resources>
<string name="app_name" translatable="false">Interface</string>
<string name="home">Home</string>
<string name="people">People</string>
<string name="web_view_action_open_in_browser" translatable="false">Open in browser</string>
<string name="web_view_action_share" translatable="false">Share link</string>
<string name="web_view_action_share_subject" translatable="false">Shared a link</string>
@ -21,5 +22,11 @@
<string name="search_no_results">No places exist with that name</string>
<string name="privacyPolicy">Privacy Policy</string>
<string name="your_last_location">Your Last Location</string>
<string name="online">Online</string>
<!-- tags -->
<string name="tagFragmentHome">tagFragmentHome</string>
<string name="tagFragmentLogin">tagFragmentLogin</string>
<string name="tagFragmentPolicy">tagFragmentPolicy</string>
<string name="tagFragmentPeople">tagFragmentPeople</string>
</resources>

View file

@ -28,6 +28,7 @@ allprojects {
repositories {
jcenter()
google()
mavenCentral()
}
}

View file

@ -4,8 +4,8 @@ set(EXTERNAL_NAME serverless-content)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC70v2.zip
URL_MD5 35fcc8e635e71d0b00a08455a2582448
URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC72.zip
URL_MD5 b1d8faf9266bfbff88274a484911eb99
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""

View file

@ -8,290 +8,224 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
function(global_append varName varValue)
get_property(LOCAL_LIST GLOBAL PROPERTY ${varName})
list(APPEND LOCAL_LIST ${varValue})
set_property(GLOBAL PROPERTY ${varName} ${LOCAL_LIST})
endfunction()
function(AUTOSCRIBE_SHADER SHADER_FILE)
# Grab include files
foreach(includeFile ${ARGN})
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
endforeach()
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
endforeach()
#Extract the unique include shader paths
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
#message(${TARGET_NAME} Hifi for includes ${INCLUDES})
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
endforeach()
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
#message(ready for includes ${SHADER_INCLUDES_PATHS})
# make the scribe include arguments
set(SCRIBE_INCLUDES)
foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS})
set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/)
endforeach()
# Define the final name of the generated shader file
get_filename_component(SHADER_TARGET ${SHADER_FILE} NAME_WE)
get_filename_component(SHADER_EXT ${SHADER_FILE} EXT)
if(SHADER_EXT STREQUAL .slv)
set(SHADER_TYPE vert)
elseif(${SHADER_EXT} STREQUAL .slf)
set(SHADER_TYPE frag)
elseif(${SHADER_EXT} STREQUAL .slg)
set(SHADER_TYPE geom)
endif()
file(MAKE_DIRECTORY "${SHADERS_DIR}/${SHADER_LIB}")
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_LIB}/${SHADER_TARGET}.${SHADER_TYPE}")
set(SCRIBE_COMMAND scribe)
# Target dependant Custom rule on the SHADER_FILE
if (APPLE)
set(GLPROFILE MAC_GL)
elseif (ANDROID)
set(GLPROFILE LINUX_GL)
set(SCRIBE_COMMAND ${NATIVE_SCRIBE})
elseif (UNIX)
set(GLPROFILE LINUX_GL)
else ()
set(GLPROFILE PC_GL)
endif()
set(SCRIBE_ARGS -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
add_custom_command(
OUTPUT ${SHADER_TARGET}
COMMAND ${SCRIBE_COMMAND} ${SCRIBE_ARGS}
DEPENDS ${SHADER_FILE} ${SCRIBE_COMMAND} ${SHADER_INCLUDE_FILES}
)
#output the generated file name
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE)
endfunction()
macro(AUTOSCRIBE_APPEND_SHADER_SOURCES)
if (NOT("${ARGN}" STREQUAL ""))
set_property(GLOBAL PROPERTY ${TARGET_NAME}_SHADER_SOURCES "${ARGN}")
global_append(GLOBAL_SHADER_LIBS ${TARGET_NAME})
global_append(GLOBAL_SHADER_SOURCES "${ARGN}")
endif()
endmacro()
macro(AUTOSCRIBE_SHADER_LIB)
unset(HIFI_LIBRARIES_SHADER_INCLUDE_FILES)
set(SRC_FOLDER "${CMAKE_SOURCE_DIR}/libraries/${TARGET_NAME}/src")
file(GLOB_RECURSE SHADER_INCLUDE_FILES ${SRC_FOLDER}/*.slh)
file(GLOB_RECURSE SHADER_VERTEX_FILES ${SRC_FOLDER}/*.slv)
file(GLOB_RECURSE SHADER_FRAGMENT_FILES ${SRC_FOLDER}/*.slf)
file(GLOB_RECURSE SHADER_GEOMETRY_FILES ${SRC_FOLDER}/*.slg)
file(GLOB_RECURSE SHADER_COMPUTE_FILES ${SRC_FOLDER}/*.slc)
unset(SHADER_SOURCE_FILES)
list(APPEND SHADER_SOURCE_FILES ${SHADER_VERTEX_FILES})
list(APPEND SHADER_SOURCE_FILES ${SHADER_FRAGMENT_FILES})
list(APPEND SHADER_SOURCE_FILES ${SHADER_GEOMETRY_FILES})
list(APPEND SHADER_SOURCE_FILES ${SHADER_COMPUTE_FILES})
unset(LOCAL_SHADER_SOURCES)
list(APPEND LOCAL_SHADER_SOURCES ${SHADER_SOURCE_FILES})
list(APPEND LOCAL_SHADER_SOURCES ${SHADER_INCLUDE_FILES})
AUTOSCRIBE_APPEND_SHADER_SOURCES(${LOCAL_SHADER_SOURCES})
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
foreach(HIFI_LIBRARY ${ARGN})
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src)
endforeach()
endmacro()
macro(AUTOSCRIBE_PROGRAM)
set(oneValueArgs NAME VERTEX FRAGMENT GEOMETRY COMPUTE)
cmake_parse_arguments(AUTOSCRIBE_PROGRAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (NOT (DEFINED AUTOSCRIBE_PROGRAM_NAME))
message(FATAL_ERROR "Programs must have a name and both a vertex and fragment shader")
endif()
if (NOT (DEFINED AUTOSCRIBE_PROGRAM_VERTEX))
set(AUTOSCRIBE_PROGRAM_VERTEX ${AUTOSCRIBE_PROGRAM_NAME})
endif()
if (NOT (DEFINED AUTOSCRIBE_PROGRAM_FRAGMENT))
set(AUTOSCRIBE_PROGRAM_FRAGMENT ${AUTOSCRIBE_PROGRAM_NAME})
endif()
if (NOT (${AUTOSCRIBE_PROGRAM_VERTEX} MATCHES ".*::.*"))
set(AUTOSCRIBE_PROGRAM_VERTEX "vertex::${AUTOSCRIBE_PROGRAM_VERTEX}")
endif()
if (NOT (${AUTOSCRIBE_PROGRAM_FRAGMENT} MATCHES ".*::.*"))
set(AUTOSCRIBE_PROGRAM_FRAGMENT "fragment::${AUTOSCRIBE_PROGRAM_FRAGMENT}")
endif()
unset(AUTOSCRIBE_PROGRAM_MAP)
list(APPEND AUTOSCRIBE_PROGRAM_MAP AUTOSCRIBE_PROGRAM_VERTEX)
list(APPEND AUTOSCRIBE_PROGRAM_MAP ${AUTOSCRIBE_PROGRAM_VERTEX})
list(APPEND AUTOSCRIBE_PROGRAM_MAP AUTOSCRIBE_PROGRAM_FRAGMENT)
list(APPEND AUTOSCRIBE_PROGRAM_MAP ${AUTOSCRIBE_PROGRAM_FRAGMENT})
global_append(${TARGET_NAME}_PROGRAMS ${AUTOSCRIBE_PROGRAM_NAME})
set_property(GLOBAL PROPERTY ${AUTOSCRIBE_PROGRAM_NAME} "${AUTOSCRIBE_PROGRAM_MAP}")
endmacro()
macro(unpack_map)
set(MAP_VAR "${ARGN}")
list(LENGTH MAP_VAR MAP_SIZE)
MATH(EXPR MAP_ENTRY_RANGE "(${MAP_SIZE} / 2) - 1")
foreach(INDEX RANGE ${MAP_ENTRY_RANGE})
MATH(EXPR INDEX_NAME "${INDEX} * 2")
MATH(EXPR INDEX_VAL "${INDEX_NAME} + 1")
list(GET MAP_VAR ${INDEX_NAME} VAR_NAME)
list(GET MAP_VAR ${INDEX_VAL} VAR_VAL)
set(${VAR_NAME} ${VAR_VAL})
macro(AUTOSCRIBE_SHADER)
message(STATUS "Processing shader ${SHADER_FILE}")
unset(SHADER_INCLUDE_FILES)
# Grab include files
foreach(includeFile ${ARGN})
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
endforeach()
endmacro()
macro(PROCESS_SHADER_FILE)
AUTOSCRIBE_SHADER(${SHADER} ${ALL_SHADER_HEADERS} ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
set_property(SOURCE ${AUTOSCRIBE_GENERATED_FILE} PROPERTY SKIP_AUTOMOC ON)
source_group("Compiled/${SHADER_LIB}" FILES ${AUTOSCRIBE_GENERATED_FILE})
set(REFLECTED_SHADER "${AUTOSCRIBE_GENERATED_FILE}.json")
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
endforeach()
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
#Extract the unique include shader paths
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
endforeach()
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
#message(ready for includes ${SHADER_INCLUDES_PATHS})
# make the scribe include arguments
set(SCRIBE_INCLUDES)
foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS})
set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/)
endforeach()
# Define the final name of the generated shader file
get_filename_component(SHADER_NAME ${SHADER_FILE} NAME_WE)
get_filename_component(SHADER_EXT ${SHADER_FILE} EXT)
if(SHADER_EXT STREQUAL .slv)
set(SHADER_TYPE vert)
elseif(${SHADER_EXT} STREQUAL .slf)
set(SHADER_TYPE frag)
elseif(${SHADER_EXT} STREQUAL .slg)
set(SHADER_TYPE geom)
endif()
file(MAKE_DIRECTORY "${SHADERS_DIR}/${SHADER_LIB}")
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_LIB}/${SHADER_NAME}.${SHADER_TYPE}")
file(TO_CMAKE_PATH "${SHADER_TARGET}" COMPILED_SHADER)
set(REFLECTED_SHADER "${COMPILED_SHADER}.json")
set(SCRIBE_ARGS -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
# Generate the frag/vert file
add_custom_command(
OUTPUT ${SHADER_TARGET}
COMMAND ${SCRIBE_COMMAND} ${SCRIBE_ARGS}
DEPENDS ${SHADER_FILE} ${SCRIBE_COMMAND} ${SHADER_INCLUDE_FILES})
# Generate the json reflection
# FIXME move to spirv-cross for this task after we have spirv compatible shaders
add_custom_command(
OUTPUT ${REFLECTED_SHADER}
COMMAND ${SHREFLECT_COMMAND} ${COMPILED_SHADER}
DEPENDS ${SHREFLECT_DEPENDENCY} ${COMPILED_SHADER})
#output the generated file name
source_group("Compiled/${SHADER_LIB}" FILES ${COMPILED_SHADER})
set_property(SOURCE ${COMPILED_SHADER} PROPERTY SKIP_AUTOMOC ON)
list(APPEND COMPILED_SHADERS ${COMPILED_SHADER})
source_group("Reflected/${SHADER_LIB}" FILES ${REFLECTED_SHADER})
list(APPEND COMPILED_SHADERS ${AUTOSCRIBE_GENERATED_FILE})
get_filename_component(ENUM_NAME ${SHADER} NAME_WE)
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${ENUM_NAME} = ${SHADER_COUNT},\n")
list(APPEND REFLECTED_SHADERS ${REFLECTED_SHADER})
string(CONCAT SHADER_QRC "${SHADER_QRC}" "<file alias=\"${SHADER_COUNT}\">${COMPILED_SHADER}</file>\n")
string(CONCAT SHADER_QRC "${SHADER_QRC}" "<file alias=\"${SHADER_COUNT}_reflection\">${REFLECTED_SHADER}</file>\n")
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${SHADER_NAME} = ${SHADER_COUNT},\n")
MATH(EXPR SHADER_COUNT "${SHADER_COUNT}+1")
endmacro()
macro(AUTOSCRIBE_SHADER_FINISH)
get_property(GLOBAL_SHADER_LIBS GLOBAL PROPERTY GLOBAL_SHADER_LIBS)
list(REMOVE_DUPLICATES GLOBAL_SHADER_LIBS)
set(SHADER_COUNT 0)
set(PROGRAM_COUNT 0)
macro(AUTOSCRIBE_SHADER_LIB)
if (NOT ("${TARGET_NAME}" STREQUAL "shaders"))
message(FATAL_ERROR "AUTOSCRIBE_SHADER_LIB can only be used by the shaders library")
endif()
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES "${CMAKE_SOURCE_DIR}/libraries/${SHADER_LIB}/src")
string(REGEX REPLACE "[-]" "_" SHADER_NAMESPACE ${SHADER_LIB})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace ${SHADER_NAMESPACE} {\n")
set(SRC_FOLDER "${CMAKE_SOURCE_DIR}/libraries/${ARGN}/src")
# Process the scribe headers
file(GLOB_RECURSE SHADER_INCLUDE_FILES ${SRC_FOLDER}/*.slh)
if(SHADER_INCLUDE_FILES)
source_group("${SHADER_LIB}/Headers" FILES ${SHADER_INCLUDE_FILES})
list(APPEND ALL_SHADER_HEADERS ${SHADER_INCLUDE_FILES})
list(APPEND ALL_SCRIBE_SHADERS ${SHADER_INCLUDE_FILES})
endif()
file(GLOB_RECURSE SHADER_VERTEX_FILES ${SRC_FOLDER}/*.slv)
if (SHADER_VERTEX_FILES)
source_group("${SHADER_LIB}/Vertex" FILES ${SHADER_VERTEX_FILES})
list(APPEND ALL_SCRIBE_SHADERS ${SHADER_VERTEX_FILES})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace vertex { enum {\n")
foreach(SHADER_FILE ${SHADER_VERTEX_FILES})
AUTOSCRIBE_SHADER(${ALL_SHADER_HEADERS})
endforeach()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // vertex \n")
endif()
file(GLOB_RECURSE SHADER_FRAGMENT_FILES ${SRC_FOLDER}/*.slf)
if (SHADER_FRAGMENT_FILES)
source_group("${SHADER_LIB}/Fragment" FILES ${SHADER_FRAGMENT_FILES})
list(APPEND ALL_SCRIBE_SHADERS ${SHADER_FRAGMENT_FILES})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace fragment { enum {\n")
foreach(SHADER_FILE ${SHADER_FRAGMENT_FILES})
AUTOSCRIBE_SHADER(${ALL_SHADER_HEADERS})
endforeach()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // fragment \n")
endif()
# FIXME add support for geometry, compute and tesselation shaders
#file(GLOB_RECURSE SHADER_GEOMETRY_FILES ${SRC_FOLDER}/*.slg)
#file(GLOB_RECURSE SHADER_COMPUTE_FILES ${SRC_FOLDER}/*.slc)
# the programs
file(GLOB_RECURSE SHADER_PROGRAM_FILES ${SRC_FOLDER}/*.slp)
if (SHADER_PROGRAM_FILES)
source_group("${SHADER_LIB}/Program" FILES ${SHADER_PROGRAM_FILES})
list(APPEND ALL_SCRIBE_SHADERS ${SHADER_PROGRAM_FILES})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace program { enum {\n")
foreach(PROGRAM_FILE ${SHADER_PROGRAM_FILES})
get_filename_component(PROGRAM_NAME ${PROGRAM_FILE} NAME_WE)
set(AUTOSCRIBE_PROGRAM_FRAGMENT ${PROGRAM_NAME})
file(READ ${PROGRAM_FILE} PROGRAM_CONFIG)
set(AUTOSCRIBE_PROGRAM_VERTEX ${PROGRAM_NAME})
set(AUTOSCRIBE_PROGRAM_FRAGMENT ${PROGRAM_NAME})
if (NOT("${PROGRAM_CONFIG}" STREQUAL ""))
string(REGEX MATCH ".*VERTEX +([_\\:A-Z0-9a-z]+)" MVERT ${PROGRAM_CONFIG})
if (CMAKE_MATCH_1)
set(AUTOSCRIBE_PROGRAM_VERTEX ${CMAKE_MATCH_1})
endif()
string(REGEX MATCH ".*FRAGMENT +([_:A-Z0-9a-z]+)" MFRAG ${PROGRAM_CONFIG})
if (CMAKE_MATCH_1)
set(AUTOSCRIBE_PROGRAM_FRAGMENT ${CMAKE_MATCH_1})
endif()
endif()
if (NOT (${AUTOSCRIBE_PROGRAM_VERTEX} MATCHES ".*::.*"))
set(AUTOSCRIBE_PROGRAM_VERTEX "vertex::${AUTOSCRIBE_PROGRAM_VERTEX}")
endif()
if (NOT (${AUTOSCRIBE_PROGRAM_FRAGMENT} MATCHES ".*::.*"))
set(AUTOSCRIBE_PROGRAM_FRAGMENT "fragment::${AUTOSCRIBE_PROGRAM_FRAGMENT}")
endif()
set(PROGRAM_ENTRY "${PROGRAM_NAME} = (${AUTOSCRIBE_PROGRAM_VERTEX} << 16) | ${AUTOSCRIBE_PROGRAM_FRAGMENT},\n")
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${PROGRAM_ENTRY}")
string(CONCAT SHADER_PROGRAMS_ARRAY "${SHADER_PROGRAMS_ARRAY} ${SHADER_NAMESPACE}::program::${PROGRAM_NAME},\n")
endforeach()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // program \n")
endif()
# Finish the shader enums
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "} // namespace ${SHADER_NAMESPACE}\n")
#file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
#foreach(HIFI_LIBRARY ${ARGN})
#list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src)
#endforeach()
#endif()
endmacro()
macro(AUTOSCRIBE_SHADER_LIBS)
set(SCRIBE_COMMAND scribe)
set(SHREFLECT_COMMAND shreflect)
set(SHREFLECT_DEPENDENCY shreflect)
# Target dependant Custom rule on the SHADER_FILE
if (ANDROID)
set(GLPROFILE LINUX_GL)
set(SCRIBE_COMMAND ${NATIVE_SCRIBE})
set(SHREFLECT_COMMAND ${NATIVE_SHREFLECT})
unset(SHREFLECT_DEPENDENCY)
else()
if (APPLE)
set(GLPROFILE MAC_GL)
elseif(UNIX)
set(GLPROFILE LINUX_GL)
else()
set(GLPROFILE PC_GL)
endif()
endif()
# Start the shader IDs
set(SHADER_COUNT 1)
set(SHADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders")
set(SHADER_ENUMS "")
file(MAKE_DIRECTORY ${SHADERS_DIR})
unset(COMPILED_SHADERS)
foreach(SHADER_LIB ${GLOBAL_SHADER_LIBS})
get_property(LIB_SHADER_SOURCES GLOBAL PROPERTY ${SHADER_LIB}_SHADER_SOURCES)
get_property(LIB_PROGRAMS GLOBAL PROPERTY ${SHADER_LIB}_PROGRAMS)
list(REMOVE_DUPLICATES LIB_SHADER_SOURCES)
string(REGEX REPLACE "[-]" "_" SHADER_NAMESPACE ${SHADER_LIB})
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES "${CMAKE_SOURCE_DIR}/libraries/${SHADER_LIB}/src")
unset(VERTEX_SHADERS)
unset(FRAGMENT_SHADERS)
unset(SHADER_HEADERS)
foreach(SHADER_FILE ${LIB_SHADER_SOURCES})
if (SHADER_FILE MATCHES ".*\\.slv")
list(APPEND VERTEX_SHADERS ${SHADER_FILE})
elseif (SHADER_FILE MATCHES ".*\\.slf")
list(APPEND FRAGMENT_SHADERS ${SHADER_FILE})
elseif (SHADER_FILE MATCHES ".*\\.slh")
list(APPEND SHADER_HEADERS ${SHADER_FILE})
endif()
endforeach()
if (DEFINED SHADER_HEADERS)
list(REMOVE_DUPLICATES SHADER_HEADERS)
source_group("${SHADER_LIB}/Headers" FILES ${SHADER_HEADERS})
list(APPEND ALL_SHADER_HEADERS ${SHADER_HEADERS})
list(APPEND ALL_SCRIBE_SHADERS ${SHADER_HEADERS})
endif()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace ${SHADER_NAMESPACE} {\n")
if (DEFINED VERTEX_SHADERS)
list(REMOVE_DUPLICATES VERTEX_SHADERS)
source_group("${SHADER_LIB}/Vertex" FILES ${VERTEX_SHADERS})
list(APPEND ALL_SCRIBE_SHADERS ${VERTEX_SHADERS})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace vertex { enum {\n")
foreach(SHADER ${VERTEX_SHADERS})
process_shader_file()
endforeach()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // vertex \n")
endif()
if (DEFINED FRAGMENT_SHADERS)
list(REMOVE_DUPLICATES FRAGMENT_SHADERS)
source_group("${SHADER_LIB}/Fragment" FILES ${FRAGMENT_SHADERS})
list(APPEND ALL_SCRIBE_SHADERS ${FRAGMENT_SHADERS})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace fragment { enum {\n")
foreach(SHADER ${FRAGMENT_SHADERS})
process_shader_file()
endforeach()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // fragment \n")
endif()
if (DEFINED LIB_PROGRAMS)
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace program { enum {\n")
foreach(LIB_PROGRAM ${LIB_PROGRAMS})
get_property(LIB_PROGRAM_MAP GLOBAL PROPERTY ${LIB_PROGRAM})
unpack_map(${LIB_PROGRAM_MAP})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${LIB_PROGRAM} = (${AUTOSCRIBE_PROGRAM_VERTEX} << 16) | ${AUTOSCRIBE_PROGRAM_FRAGMENT},\n")
MATH(EXPR PROGRAM_COUNT "${PROGRAM_COUNT}+1")
list(APPEND SHADER_ALL_PROGRAMS "${SHADER_NAMESPACE}::program::${LIB_PROGRAM}")
endforeach()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // program \n")
endif()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "} // namespace ${SHADER_NAMESPACE}\n")
#
# Scribe generation & program defintiion
#
foreach(SHADER_LIB ${ARGN})
AUTOSCRIBE_SHADER_LIB(${SHADER_LIB})
endforeach()
set(SHADER_PROGRAMS_ARRAY "")
foreach(SHADER_PROGRAM ${SHADER_ALL_PROGRAMS})
string(CONCAT SHADER_PROGRAMS_ARRAY "${SHADER_PROGRAMS_ARRAY}" " ${SHADER_PROGRAM},\n")
endforeach()
# Generate the library files
configure_file(
ShaderEnums.cpp.in
${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp)
configure_file(
ShaderEnums.h.in
${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h)
configure_file(
shaders.qrc.in
${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc)
set(SHREFLECT_COMMAND shreflect)
set(SHREFLECT_DEPENDENCY shreflect)
if (ANDROID)
set(SHREFLECT_COMMAND ${NATIVE_SHREFLECT})
unset(SHREFLECT_DEPENDENCY)
endif()
set(SHADER_COUNT 0)
foreach(COMPILED_SHADER ${COMPILED_SHADERS})
set(REFLECTED_SHADER "${COMPILED_SHADER}.json")
list(APPEND COMPILED_SHADER_REFLECTIONS ${REFLECTED_SHADER})
string(CONCAT SHADER_QRC "${SHADER_QRC}" "<file alias=\"${SHADER_COUNT}\">${COMPILED_SHADER}</file>\n")
string(CONCAT SHADER_QRC "${SHADER_QRC}" "<file alias=\"${SHADER_COUNT}_reflection\">${REFLECTED_SHADER}</file>\n")
MATH(EXPR SHADER_COUNT "${SHADER_COUNT}+1")
add_custom_command(
OUTPUT ${REFLECTED_SHADER}
COMMAND ${SHREFLECT_COMMAND} ${COMPILED_SHADER}
DEPENDS ${SHREFLECT_DEPENDENCY} ${COMPILED_SHADER}
)
endforeach()
set(AUTOSCRIBE_SHADER_LIB_SRC "${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h;${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp")
set(QT_RESOURCES_FILE ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc)
# Custom targets required to force generation of the shaders via scribe
add_custom_target(scribe_shaders SOURCES ${ALL_SCRIBE_SHADERS})
add_custom_target(compiled_shaders SOURCES ${COMPILED_SHADERS})
add_custom_target(reflected_shaders SOURCES ${COMPILED_SHADER_REFLECTIONS})
add_custom_target(reflected_shaders SOURCES ${REFLECTED_SHADERS})
set_target_properties(scribe_shaders PROPERTIES FOLDER "Shaders")
set_target_properties(compiled_shaders PROPERTIES FOLDER "Shaders")
set_target_properties(reflected_shaders PROPERTIES FOLDER "Shaders")
configure_file(
ShaderEnums.cpp.in
${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp
)
configure_file(
ShaderEnums.h.in
${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h
)
configure_file(
shaders.qrc.in
${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc
)
set(AUTOSCRIBE_SHADER_LIB_SRC "${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h;${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp")
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${COMPILED_SHADERS})
set(QT_RESOURCES_FILE ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc)
get_property(GLOBAL_SHADER_SOURCES GLOBAL PROPERTY GLOBAL_SHADER_SOURCES)
list(REMOVE_DUPLICATES GLOBAL_SHADER_SOURCES)
endmacro()

View file

@ -51,6 +51,10 @@ macro(SET_PACKAGING_PARAMETERS)
set(USE_STABLE_GLOBAL_SERVICES 1)
endif ()
if (NOT BYPASS_SIGNING)
set(BYPASS_SIGNING 0)
endif ()
elseif (RELEASE_TYPE STREQUAL "PR")
set(DEPLOY_PACKAGE TRUE)
set(PR_BUILD 1)

View file

@ -50,3 +50,4 @@ set(SERVER_COMPONENT_CONDITIONAL "@SERVER_COMPONENT_CONDITIONAL@")
set(CLIENT_COMPONENT_CONDITIONAL "@CLIENT_COMPONENT_CONDITIONAL@")
set(INSTALLER_TYPE "@INSTALLER_TYPE@")
set(APP_USER_MODEL_ID "@APP_USER_MODEL_ID@")
set(BYPASS_SIGNING "@BYPASS_SIGNING@")

View file

@ -130,7 +130,11 @@
; The Inner invocation has written an uninstaller binary for us.
; We need to sign it if it's a production or PR build.
!if @PRODUCTION_BUILD@ == 1
!system '"@SIGNTOOL_EXECUTABLE@" sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 $%TEMP%\@UNINSTALLER_NAME@' = 0
!if @BYPASS_SIGNING@ == 1
!warning "BYPASS_SIGNING set - installer will not be signed"
!else
!system '"@SIGNTOOL_EXECUTABLE@" sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 $%TEMP%\@UNINSTALLER_NAME@' = 0
!endif
!endif
; Good. Now we can carry on writing the real installer.

View file

@ -2439,8 +2439,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
}
} else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) {
const QString ALL_NODE_DELETE_REGEX_STRING = QString("\\%1\\/?$").arg(URI_NODES);
const QString NODE_DELETE_REGEX_STRING = QString("\\%1\\/(%2)\\/$").arg(URI_NODES).arg(UUID_REGEX_STRING);
const QString ALL_NODE_DELETE_REGEX_STRING = QString("%1/?$").arg(URI_NODES);
const QString NODE_DELETE_REGEX_STRING = QString("%1/(%2)$").arg(URI_NODES).arg(UUID_REGEX_STRING);
QRegExp allNodesDeleteRegex(ALL_NODE_DELETE_REGEX_STRING);
QRegExp nodeDeleteRegex(NODE_DELETE_REGEX_STRING);

View file

@ -266,19 +266,10 @@ class RenderEventHandler : public QObject {
using Parent = QObject;
Q_OBJECT
public:
RenderEventHandler(QOpenGLContext* context) {
_renderContext = new OffscreenGLCanvas();
_renderContext->setObjectName("RenderContext");
_renderContext->create(context);
if (!_renderContext->makeCurrent()) {
qFatal("Unable to make rendering context current");
}
_renderContext->doneCurrent();
RenderEventHandler() {
// Transfer to a new thread
moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) {
hifi::qt::addBlockingForbiddenThread("Render", renderThread);
_renderContext->moveToThreadWithContext(renderThread);
qApp->_lastTimeRendered.start();
}, std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority);
}
@ -288,9 +279,6 @@ private:
setObjectName("Render");
PROFILE_SET_THREAD_NAME("Render");
setCrashAnnotation("render_thread_id", std::to_string((size_t)QThread::currentThreadId()));
if (!_renderContext->makeCurrent()) {
qFatal("Unable to make rendering context current on render thread");
}
}
void render() {
@ -311,8 +299,6 @@ private:
}
return Parent::event(event);
}
OffscreenGLCanvas* _renderContext { nullptr };
};
@ -2695,26 +2681,14 @@ void Application::initializeGL() {
}
}
// Build an offscreen GL context for the main thread.
_offscreenContext = new OffscreenGLCanvas();
_offscreenContext->setObjectName("MainThreadContext");
_offscreenContext->create(_glWidget->qglContext());
if (!_offscreenContext->makeCurrent()) {
qFatal("Unable to make offscreen context current");
}
_offscreenContext->doneCurrent();
_offscreenContext->setThreadContext();
_renderEventHandler = new RenderEventHandler();
// Build an offscreen GL context for the main thread.
_glWidget->makeCurrent();
glClearColor(0.2f, 0.2f, 0.2f, 1);
glClear(GL_COLOR_BUFFER_BIT);
_glWidget->swapBuffers();
// Move the GL widget context to the render event handler thread
_renderEventHandler = new RenderEventHandler(_glWidget->qglContext());
if (!_offscreenContext->makeCurrent()) {
qFatal("Unable to make offscreen context current");
}
// Create the GPU backend
@ -2727,9 +2701,6 @@ void Application::initializeGL() {
_gpuContext = std::make_shared<gpu::Context>();
DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext);
// Restore the default main thread context
_offscreenContext->makeCurrent();
}
static const QString SPLASH_SKYBOX{ "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" };
@ -2768,8 +2739,6 @@ void Application::initializeDisplayPlugins() {
// Submit a default frame to render until the engine starts up
updateRenderArgs(0.0f);
_offscreenContext->makeCurrent();
#define ENABLE_SPLASH_FRAME 0
#if ENABLE_SPLASH_FRAME
{
@ -2811,8 +2780,6 @@ void Application::initializeDisplayPlugins() {
}
void Application::initializeRenderEngine() {
_offscreenContext->makeCurrent();
// FIXME: on low end systems os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread.
DeadlockWatchdogThread::withPause([&] {
// Set up the render engine
@ -4562,7 +4529,6 @@ void Application::idle() {
if (offscreenUi->size() != fromGlm(uiSize)) {
qCDebug(interfaceapp) << "Device pixel ratio changed, triggering resize to " << uiSize;
offscreenUi->resize(fromGlm(uiSize));
_offscreenContext->makeCurrent();
}
}
@ -4620,10 +4586,6 @@ void Application::idle() {
bool showWarnings = getLogger()->extraDebugging();
PerformanceWarning warn(showWarnings, "idle()");
if (!_offscreenContext->makeCurrent()) {
qFatal("Unable to make main thread context current");
}
{
_gameWorkload.updateViews(_viewFrustum, getMyAvatar()->getHeadPosition());
_gameWorkload._engine->run();
@ -4951,7 +4913,6 @@ QVector<EntityItemID> Application::pasteEntities(float x, float y, float z) {
}
void Application::init() {
_offscreenContext->makeCurrent();
// Make sure Login state is up to date
DependencyManager::get<DialogsManager>()->toggleLoginDialog();
if (!DISABLE_DEFERRED) {
@ -8342,7 +8303,7 @@ QOpenGLContext* Application::getPrimaryContext() {
}
bool Application::makeRenderingContextCurrent() {
return _offscreenContext->makeCurrent();
return true;
}
bool Application::isForeground() const {

View file

@ -81,7 +81,6 @@
#include "Sound.h"
class OffscreenGLCanvas;
class GLCanvas;
class FaceTracker;
class MainWindow;
@ -554,7 +553,6 @@ private:
bool _previousSessionCrashed;
OffscreenGLCanvas* _offscreenContext { nullptr };
DisplayPluginPointer _displayPlugin;
QMetaObject::Connection _displayPluginPresentConnection;
mutable std::mutex _displayPluginLock;

View file

@ -277,6 +277,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
sortedAvatars.pop();
}
if (_shouldRender) {
qApp->getMain3DScene()->enqueueTransaction(transaction);
}
_numAvatarsUpdated = numAvatarsUpdated;
_numAvatarsNotUpdated = numAVatarsNotUpdated;

View file

@ -1,5 +1,4 @@
set(TARGET_NAME avatars-renderer)
AUTOSCRIBE_SHADER_LIB(gpu graphics render render-utils)
setup_hifi_library(Network Script)
link_hifi_libraries(shared gpu graphics animation model-networking script-engine render render-utils image trackers entities-renderer)
include_hifi_library_headers(avatars)

View file

@ -1,5 +1,4 @@
set(TARGET_NAME display-plugins)
AUTOSCRIBE_SHADER_LIB(gpu display-plugins)
setup_hifi_library(Gui)
link_hifi_libraries(shared shaders plugins ui-plugins gl ui render-utils ${PLATFORM_GL_BACKEND})
include_hifi_library_headers(gpu)

View file

@ -0,0 +1 @@
VERTEX gpu::vertex::DrawUnitQuadTexcoord

View file

@ -0,0 +1 @@
VERTEX gpu::vertex::DrawUnitQuadTexcoord

View file

@ -0,0 +1,3 @@
VERTEX DrawTransformVertexPosition
FRAGMENT DrawColor
r

View file

@ -0,0 +1,2 @@
VERTEX DrawVertexPosition
FRAGMENT DrawNada

View file

@ -0,0 +1,2 @@
VERTEX DrawUnitQuadTexcoord
FRAGMENT DrawTexture

View file

@ -0,0 +1,2 @@
VERTEX DrawTexcoordRectTransformUnitQuad
FRAGMENT DrawTextureOpaque

View file

@ -0,0 +1,2 @@
VERTEX DrawTransformUnitQuad
FRAGMENT DrawTextureOpaque

View file

@ -0,0 +1,2 @@
VERTEX DrawUnitQuadTexcoord
FRAGMENT DrawTextureOpaque

View file

@ -0,0 +1,2 @@
VERTEX gpu::vertex::DrawTransformUnitQuad
FRAGMENT BloomApply

View file

@ -0,0 +1,2 @@
VERTEX gpu::vertex::DrawTransformUnitQuad
FRAGMENT BloomThreshold

View file

@ -0,0 +1 @@
VERTEX deferred_light

View file

@ -0,0 +1 @@
VERTEX deferred_light

View file

@ -0,0 +1 @@
VERTEX deferred_light

View file

@ -0,0 +1 @@
VERTEX deferred_light

View file

@ -0,0 +1 @@
VERTEX model

View file

@ -0,0 +1 @@
VERTEX model_normal_map

View file

@ -0,0 +1,2 @@
VERTEX model_normal_map
FRAGMENT forward_model_translucent

View file

@ -0,0 +1 @@
VERTEX model

View file

@ -0,0 +1 @@
VERTEX model

View file

@ -0,0 +1 @@
VERTEX simple

View file

@ -0,0 +1 @@
VERTEX simple

View file

@ -0,0 +1 @@
VERTEX simple

View file

@ -0,0 +1,2 @@
VERTEX skin_model
FRAGMENT forward_model

View file

@ -0,0 +1,2 @@
VERTEX skin_model_dq
FRAGMENT forward_model

View file

@ -0,0 +1,2 @@
VERTEX skin_model_normal_map
FRAGMENT forward_model_normal_map

View file

@ -0,0 +1,2 @@
VERTEX skin_model_normal_map_dq
FRAGMENT forward_model_normal_map

View file

@ -0,0 +1,2 @@
VERTEX skin_model
FRAGMENT forward_model_translucent

View file

@ -0,0 +1,2 @@
VERTEX skin_model_dq
FRAGMENT forward_model_translucent

View file

@ -0,0 +1,2 @@
VERTEX skin_model_normal_map
FRAGMENT forward_model_translucent

View file

@ -0,0 +1,2 @@
VERTEX skin_model_normal_map_dq
FRAGMENT forward_model_translucent

View file

@ -0,0 +1 @@
VERTEX gpu::vertex::DrawUnitQuadTexcoord

View file

@ -0,0 +1 @@
VERTEX standardTransformPNTC

View file

@ -0,0 +1,2 @@
VERTEX gpu::vertex::DrawViewportQuadTransformTexcoord
FRAGMENT Haze

View file

@ -0,0 +1,2 @@
VERTEX gpu::vertex::DrawViewportQuadTransformTexcoord
FRAGMENT Highlight

View file

@ -0,0 +1,2 @@
VERTEX Highlight_aabox
FRAGMENT nop

View file

@ -0,0 +1,2 @@
VERTEX gpu::vertex::DrawViewportQuadTransformTexcoord
FRAGMENT Highlight_filled

View file

@ -0,0 +1 @@
VERTEX gpu::vertex::DrawUnitQuadTexcoord

View file

@ -0,0 +1 @@
VERTEX gpu::vertex::DrawUnitQuadTexcoord

View file

@ -0,0 +1 @@
VERTEX deferred_light

View file

@ -0,0 +1 @@
VERTEX deferred_light

View file

@ -0,0 +1 @@
VERTEX model_fade

View file

@ -0,0 +1 @@
VERTEX model_translucent_normal_map

View file

@ -0,0 +1 @@
VERTEX model

View file

@ -0,0 +1 @@
VERTEX model_fade

View file

@ -0,0 +1 @@
VERTEX model

View file

@ -0,0 +1 @@
VERTEX model_fade

Some files were not shown because too many files have changed in this diff Show more